8

I have managed to enable inbound HTTP compression on ASP.NET (ie compression of HTTP requests, not just responses) but I am now struggling on the client side (C# / .NET 4.0 app).

I would like to:

  • add the HTTP header Content-Encoding: gzip
  • compress HTTP body with GZip

to all outbound HTTP requests emitted by a WCF channel.

Solutions that do not work so far:

  • with IClientMessageInspector I can compress the message, but it does not account for the whole HTTP body as the envelop is not compressed.
  • same for a custom message encoder, compress the message not the envelop, no impact on the HTTP request headers.

Any idea how to mimic the IHttpModule behavior (see initial response) on the client side?

Community
  • 1
  • 1
Joannes Vermorel
  • 8,976
  • 12
  • 64
  • 104
  • 2
    Not really a direct answer (so not posted as one), but I would side-step this by sending fewer bytes - in my case by swapping out the serializer for something much more compact (same data; much smaller on the wire) – Marc Gravell Dec 11 '10 at 10:09
  • (let me know if you want some details ther - it is a topic I can talk about for hours on end) – Marc Gravell Dec 11 '10 at 10:24
  • Marc, yes, less verbose serializer is also an option. One benefit of the approach here is that it completely decouples the compression issue from the message encoding, pretty much what classical HTTP compression achieves for responses. – Joannes Vermorel Dec 11 '10 at 10:42
  • Is the message encoder like the one described here http://msdn.microsoft.com/en-us/library/ms751458.aspx ? I would have expected something like that to work. – Florin Dumitrescu Dec 11 '10 at 11:52
  • Florin, tried that but so far I can't get it working for the entire HTTP request body. – Joannes Vermorel Dec 11 '10 at 13:01
  • @Joannes, it seems that there is a bug in the message encoder sample from MSDN. In the GZipMessageEncoderFactory class, CompressBuffer method, you should try replacing the *ArraySegment byteArray = new ArraySegment(bufferedBytes, messageOffset, bufferedBytes.Length - messageOffset);* line with *ArraySegment byteArray = new ArraySegment(bufferedBytes, messageOffset, totalLength);* – Florin Dumitrescu Dec 11 '10 at 18:07
  • @Florin, thanks, had already noticed that. The problem is related to the envelop that remains uncompressed though. – Joannes Vermorel Dec 12 '10 at 15:57
  • @Joannes, after applying the fix mentioned earlier, the entire message looks compressed when checking in Fiddler. Also the GZip compression is properly applied (checked in Fiddler using the AutoDecode option). I am making my tests on the sample from the WF_WCF_Samples downloaded from the link I have previously posted. Can you post any specific changes you made from that sample and an example request message that does not compress the envelope? – Florin Dumitrescu Dec 12 '10 at 20:12
  • @Florin, you're correct, and I was not. Envelop is compressed too. Still need to figure out how to add the HTTP headers, but I am definitively making progress. Thanks! – Joannes Vermorel Dec 13 '10 at 13:39
  • @Joannes, I am going to post you an answer related to the HTTP headers. I cannot continue posting in here since I need to give a code sample and it doesn't get properly formatted inside comments. – Florin Dumitrescu Dec 13 '10 at 14:50

2 Answers2

6

The message encoder described here should do the job.

I have tested using the sample downloaded from the link available in the above article (the InstallDrive\WF_WCF_Samples\WCF\Extensibility\MessageEncoder\Compression project from this) and Fiddler.

Please note that the MSDN sample has a bug which you will need to fix in order to make it properly work. In the GZipMessageEncoderFactory class, CompressBuffer method, the following line

ArraySegment<byte> byteArray = new ArraySegment<byte>(bufferedBytes, messageOffset, bufferedBytes.Length - messageOffset);

should be replaced with

ArraySegment<byte> byteArray = new ArraySegment<byte>(bufferedBytes, messageOffset, totalLength);

After applying the above fix the entire message body would be compressed.

In order to check that the compression is correct you can use the AutoDecode option from Fiddler. However, AutoDecode will only decompress the message if it has a Content-Encoding: gzip HTTP header.

Adding HTTP headers to WCF message calls is not strait forward, since WCF was designed to be transport agnostic and WCF applications should not handle elements specific to a certain transport method.

However, for the purpose of this application I was able to do it using the following piece of code:

public string Echo(string input)
{
    using (OperationContextScope opScope = new OperationContextScope((IContextChannel)base.Channel))
    {
        HttpRequestMessageProperty reqProps = new HttpRequestMessageProperty();
        reqProps.Headers["Content-Encoding"] = "gzip";
        OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = reqProps;

        return base.Channel.Echo(input);
    }
}

Echo is one of the client methods from the MSDN sample and inside it I am accessing the current operation context to add a HTTP header.

Please let me know if you need additional help.

Alex
  • 1,366
  • 19
  • 22
Florin Dumitrescu
  • 8,182
  • 4
  • 33
  • 29
-1

I would have thought that you could enable encryption to achieve compression. I think I'm right in saying that all common encryption algorithms also compress the data to avoid producing obvious patterns in the compressed data. As a side effect, your service will be more secure :)

NickG
  • 9,315
  • 16
  • 75
  • 115