We needed to add GZip compression support to a .NET 3.5sp1 client application using WCF for REST POX web services. The responses were sent compressed using GZIP, so the client needed to be able to decompress these, before passing up the stack to the Data Serialisers and application code layers.
The server in this instance is a Java EE web application returning XML, GZipped using a filter servlet. Implementing the server side filter is fairly trivial, however it's companion in .NET on the client side is not.
Since this gave me a little bit of a challenge recently (very little documentation around or good examples) I thought I'd put up a quick blog about it. It's not that there's a lot of code involved, it's understanding the WCF with sufficient clarity to be able to extend it, and debug it when it's not quite right.
One of the issues that crops up straight away is that most examples of extending the WCF for compression are based around the WS.* web service support, the original incarnation of WCF.
However, later versions of the WCF added support for REST/POX web services, and this is where I wanted to add the GZIP compression support. You can not mix WS.* and Rest (aka Web in WCF) web services in the WCF, without creating a runtime error as the WCF channel is instantiated.
So, enough of the preamble already, lets cut to the chase, what's needed?
Well, assuming you have a WebHttpBinding to start with...
WebHttpBinding webHttpBinding = new WebHttpBinding();
Then, in order to add the GZIP compression support, we need to pull apart the binding, into its constituent elements and then reassemble it, adding in the new binding element.
I enlisted the help of a content mapper to force the content to XML:
public class XMLMapper : WebContentTypeMapper
public override WebContentFormat GetMessageFormatForContentType(string contentType)
return WebContentFormat.Xml; // always
First, get the binding elements out of the WebHttpBinding, using the CreateBindingElements() function.
BindingElementCollection bec = webHttpBinding.CreateBindingElements();
WebMessageEncodingBindingElement wmbe = bec.Remove
HttpTransportBindingElement htbe = bec.Remove
wmbe.ContentTypeMapper = new XMLMapper();
GZipMessageEncodingBindingElement compBindingElement = new GZipMessageEncodingBindingElement(wmbe);
CustomBinding cb = new CustomBinding(bec);
binding = cb;
HttpRequestMessageProperty httpRequestMessageProperty = new HttpRequestMessageProperty();
Ok, so now binding is a rebuilt binding, based on WebHttpBinding where a GZIP encoder has been used to wrap the WebMessageEncodingBindingElement from the original binding's binding elements.
Note that the HttpTransportBindingElement must be the last binding element in the binding element collection (protocol stack) or a runtime error will be thrown when trying to instantiate the channel.
Now we can create the channel in the normal way:
// create a channel factory
cf = new ChannelFactory (binding, hostPath);
// create webhttpbehavior for rest / pox get/invoke behaviour support
WebHttpBehavior webHttpBehavior = new WebHttpBehavior();
webHttpBehavior.DefaultOutgoingRequestFormat = WebMessageFormat.Xml;
webHttpBehavior.DefaultOutgoingResponseFormat = WebMessageFormat.Xml;
// add webhttpbehahvior to channelfactory endpoint
// add our custom behavior...
// create our IService channel
channel = cf.CreateChannel();
So far so good, but what about this GZipMessageEncodingBindingElement?
Well, this can be found in the Microsoft WCF samples:
Detailed steps of integrating the MS WCF GZip example into your code:
Note: I had to make some minor modifications to make my client work correctly, details can be provided if anyone leaves a comment expressing an interest.
Various threads discussing similar problems:
Neomax - provide software products to extend the WCF framework, including support for compression:
Microsoft Windows SDK for Windows 7 and .NET Framework 3.5 SP1: BETA