odatawcf-data-servicesasp.net-web-apiastoriawcf-data-services-client

Support compression in .NET OData 4 Client


Problem

I have added support for http compression in our self-hosted OWIN/Katana Web API OData 4 service but I do not see how to support compression in the .NET client. I'm using OData libraries v6.5.0 and I need to support compression/decompression in the client (OData v4 Client Code Generator). I am using Deflate encoding for the compression via an ActionFilter. Everything compresses correctly on the server as confirmed via Fiddler but I do not know how to configure the client to support this now that the OData client uses the Request and Response Pipelines instead of the now defunct WritingRequest and RecievingResponse events that once supported this very scenario.

Attempts

By experimentation I found that I can hook into the ReceivingResponse event on my DataServiceContext and then call ReceivingResponseEventArgs.ResponseMessage.GetStream() but I don't know what to do to overwrite the message content correctly. If I CopyTo() on the stream, I get a null reference exception at Microsoft.OData.Core.ODataMessageReader.DetectPayloadKind(). I presume this is because the stream was read to the end and the position needs to be set back to zero but I cannot do that because the stream also throws an exception when setting the position back because it says it does not support seeking. I presume this is simply due to the stream being read-only. Even if I could copy the stream to decompress it successfully, how do I modify the response message content with the decompressed content? I don't see any hooks for this at all in the RequestPipeline or ResponsePipeline. To clarify, I want to decompress the response message content and then set it for the materialization that occurs soon after, how might I do that? Extra credit for how to also send compressed requests to the OData service. Thanks!


Solution

  • OData client use the HTTPWebRequest and HTTPWebReponse, which supports the compression well. Try setting the AutomaticDecompression of HTTPWebRequest to Deflate or GZip, in SendingRequest2 pipeline event, like this:

    private void OnSendingRequest_(object sender, SendingRequest2EventArgs args)
    {
        if (!args.IsBatchPart) // The request message is not HttpWebRequestMessage in batch part.
        {
            HTTPWebRequest request = ((HttpWebRequestMessage)args.RequestMessage).HttpWebRequest;
            request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
        } 
    }
    

    Then in response, HTTPWebResponse will decompress the stream automatically, before the materialization work.