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?
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.
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 :)