What is the easiest way to add compression to WCF

2019-01-31 03:25发布

问题:

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.

回答1:

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



回答2:

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"



回答3:

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.



回答4:

It should also be noted that you may need to add the mime type to applicationHost.config under <httpCompression><dynamicTypes> 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.