Update (12/1/2009): this seems not to work anymore. I’m still investigating on the cause as it was definitely working (I even performed some comparison benchmarks for our product) –or maybe I had some kind of hallucinations, it happens too.
If you have any idea please share in the comments below! Thanks!
Please read this post for a working solution.
The scenario is the following: you have a Silverlight 3 application that consumes a WCF web service. By default the data exchange is serialized in XML, thus the network payload quickly becomes high if your web service sends significant amounts of data.
XML content is a very good candidate for zip/gzip compression, so it’s logical to look in this direction.
The bad news is that I found no documentation or forums/blog entries about this particular case, so it took me a while to find the solution. I even played with the compression encoder WCF sample only to find that it’s done the way it is because it refers to a different scenario (but I learned a lot in the way).
The good news is that the solution is so simple it’s not even funny, that’s probably why nobody explains how to do it.
HTTP Content-Encoding
Most modern web servers support compression and so do most browsers. When you browse the web, you often receive compressed content even if you don’t notice anything. You can use Fiddler2 to realize this fact.
How it’s working: the browser tells the server what kinds of compression he supports by setting the Accept-Encoding HTTP header. For example with
Accept-Encoding: gzip, deflate
a browser is saying “I can read content compressed with the gzip or deflate algorithms”. The server then decides what is best depending on several factors (for ex. the kind of data he’s sending). If he opts for compression (let’s say gzip), he compresses the content and adds this HTTP header to the response:
Content-Encoding: gzip
The browser now knows that the content is compressed and decompresses it with the appropriate algorithm before giving it to the html parser or whatever.
This is exactly the mechanism we will leverage.
Client Side (Silverlight)
Let’s see how to prepare the client-side.
We have to do two things: 1) tell the server we support compression 2) decompress responses if they are compressed.
How? The browser does all this for you. That’s simply because any web server call made by Silverlight is handled (by default) by the browser’s HTTP stack. This means that the browser manages all the low level stuff such as adding the proper Accept-Encoding header and decompressing content based on Content-Encoding.
The whole process is completely transparent to Silverlight: we don’t have to do anything.
Wonderful, but since compression is still not happening it means we have to do something on the server.
Server Side (WCF)
Here we have to distinguish two cases: the service can be hosted in IIS or self-hosted. If it’s hosted in IIS you’ll just have to enable compression in the IIS control panel.
In my case however the service is self-hosted.
The key here is the endpoint’s binding. Silverlight 3 only supports basicHttpBinding, so your WCF service probably uses the same (as they must match). The problem is that basicHttpBinding is “basic” indeed, and cannot do advanced things like handle compression.
The trick is to use a more “advanced” binding that can handle http compression but is still compatible with the client’s basicHttpBinding. Here is a customBinding that mimics the basicHttpBinding:
<customBinding>
<binding name=“customHttpBinding“>
<textMessageEncoding messageVersion=“Soap11Addressing1”
writeEncoding=“utf-8“/>
<httpTransport />
</binding>
</customBinding>
the same in c#:
var customBinding = new CustomBinding(
new TextMessageEncodingBindingElement(
MessageVersion.Soap11,
Encoding.UTF8),
new HttpTransportBindingElement());
That’s all. Yes, nothing more is needed! This binding will automatically deal with compression the same way as IIS does.
You can fire up Fiddler2 and look at your web service calls. You can play with the Accept-Encoding header and see that the server behaves accordingly.
Maybe in some future version Silverlight will support more advanced bindings, in that case you won’t probably even need this.