views:

8174

answers:

8

I have a silverlight 2 beta 2 application that accesses a WCF web service. Because of this, it currently can only use basicHttp binding. The webservice will return fairly large amounts of XML data. This seems fairly wasteful from a bandwidth usage standpoint as the response, if zipped, would be smaller by a factor of 5 (I actually pasted the response into a txt file and zipped it.).

The request does have the "Accept-Encoding: gzip, deflate" - Is there any way have the WCF service gzip (or otherwise compress) the response?

I did find this link but it sure seems a bit complex for functionality that should be handled out-of-the-box IMHO.

OK - at first I marked the solution using the System.IO.Compression as the answer as I could never "seem" to get the IIS7 dynamic compression to work. Well, as it turns out:

  1. Dynamic Compression on IIS7 was working al along. It is just that Nikhil's Web Developer Helper plugin for IE did not show it working. My guess is that since SL hands the web service call off to the browser, that the browser handles it "under the covers" and Nikhil's tool never sees the compressed response. I was able to confirm this by using Fiddler which monitors traffic external to the browser application. In fiddler, the response was, in fact, gzip compressed!!

  2. The other problem with the System.IO.Compression solution is that System.IO.Compression does not exist in the Silverlight CLR.

So from my perspective, the EASIEST way to enable WCF compression in Silverlight is to enable Dynamic Compression in IIS7 and write no code at all.

+9  A: 

I didn't see a native way for WCF to do compression when doing a WCF project recently. I just used the System.IO.Compression namespace and made a quick compressor. Here's the code i used

public static class CompressedSerializer
{
    /// <summary>
    /// Decompresses the specified compressed data.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="compressedData">The compressed data.</param>
    /// <returns></returns>
    public static T Decompress<T>(byte[] compressedData) where T : class
    {
        T result = null;
        using (MemoryStream memory = new MemoryStream())
        {
            memory.Write(compressedData, 0, compressedData.Length);
            memory.Position = 0L;

            using (GZipStream zip= new GZipStream(memory, CompressionMode.Decompress, true))
            {
                zip.Flush();
                var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                result = formatter.Deserialize(zip) as T;
            }
        }

        return result;
    }

    /// <summary>
    /// Compresses the specified data.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="data">The data.</param>
    /// <returns></returns>
    public static byte[] Compress<T>(T data)
    {
        byte[] result = null;
        using (MemoryStream memory = new MemoryStream())
        {
            using (GZipStream zip= new GZipStream(memory, CompressionMode.Compress, true))
            {
                var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                formatter.Serialize(zip, data);
            }

            result = memory.ToArray();
        }

        return result;
    }
}

then i just had my services take in a byte array as an input, like such

void ReceiveData(byte[] data);

Worked out well for me.

Darren Kopp
This is a very useful helper class, Thank you =)
Alexandre Brisebois
Note that GZipStream isn't available in the Silverlight 2 CLR. DimeBrain have and implementation of SharpZipLib here: http://dimebrain.com/2008/06/compression-i-1.html
russau
+5  A: 

If you are using IIS7, take a look at the Compression Module. This allows you to configure compression for HTTP requests to your server.

Lance Fisher
Some caveats here: my work proxy removes the accept gzip header (wtf, right?). And you are only compressing data going to the client.
russau
+8  A: 

WS-Compression for WCF allows you to configure compression on the binding.

See WS-Compression for WCF by Pablo M. Cibraro

Alternatively, try Microsofts GZip Encoder Sample which "creates an encoder channel that uses the System.IO.Compression.GZipStream class to compress outgoing WCF messages"

Daniel Ballinger
The one caveat is that silverlight 2 does not support WS-bindings at all, just basicHttp bindings.
caryden
+2  A: 

This also allows you to do wcf compression

http://www.codeplex.com/wcfextensions

Simon
A: 

If you're stuck on IIS6 you may want to give this a read.

http://bloggingabout.net/blogs/ramon/archive/2008/11/06/wcf-and-http-gzip-deflate-compression-and-silverlight.aspx

Simon_Weaver
A: 

we bought a commercial library to do the same thing. there are a few companies out there supporting compression, 373ksfotware rings a bell as they have a trial download.

Justin
A: 

as before: the link was http://www.373ksoftware.com

Justin
+1  A: 

It should also be noted that you may need to add the mime type to applicationHost.config under section in addition to enabling compression for the site:

    <add mimeType="application/soap+msbin1" enabled="true" />

If certain dynamic responses are not being compressed (and some are) it could be a mime type issue. Use Fiddler to get the specifics associated with the request. Failed request tracing may be useful in determining whether or not IIS is even attempting to compression the response. If compression is correctly configured you will see a NO_MATCHING_CONTENT_TYPE in the "complete trace" section of the trace output.

Mike H.
That did it for me. However it should be noted the you have to set this setting in the C:\Windows\System32\inetsrv\config\applicationHost.config file because the web.config setting is ignored.Worked straight away once I changed that.
R4cOON