Aspnet Core UseResponseCompression breaks JsonHttpClient

I seem to be having trouble with the JsonHttpClient. It is not handling gzip responses properly.

            var c = new JsonHttpClient(Url);
            c.GetHttpClient().Timeout = TimeSpan.FromSeconds(25);

            Client = c.WithCache();

We recently upgraded the API it is calling to run on .Net Core and we have setup the response compression middleware. This seems to work perfectly on browser, but does not work well with the JsonHttpClient.

Any ideas? Disabling response compression middleware fixes the issue, but why would the HttpClient not handle this situation?

Not sure, the HttpClient is configured to automatically decompress Gzip and Deflate responses by default:

Where JsonHttpClient supports deserializing ServiceStack’s compressed responses as seen in CompressResponseTests.cs.

Does it work with the ServiceStack’s compressed responses? Do you know what Compression UseResponseCompression() uses? It’s not being used with any ServiceStack cached services right? as compression is added by ServiceStack in its optimized responses.

If you upgrade to v5.1.1 on MyGet you can try using the JsonServiceClient which has been recently configured to decompress using its own compression impl in this commit when it detects it hasn’t been decompressed by the underlying library. Normally decompression is handled transparently by the underlying .NET Http Client but the .NET HttpWebRequest in .NET Core uses a custom implementation over HttpClient which initially didn’t support auto decompression, which is handled in ServiceStack when detected.

I’ll commence testing some stuff now. I have a feeling ServiceStack through CacheResponse was compressing and then the ResponseCompression middleware was compressing again.

Another question regarding compression: how can I get ServiceStack to compress responses that have an Accept-Encoding: gzip header automatically? I expect this to happen regardless if cached or not and I am not going to apply an attribute to every service.

Or maybe there is a way to use ServiceStack and the aspnet ResponseCompression middleware together, so as to disable compression completely in ServiceStack and let the middleware apply compression based on the response’s mimetype.

If using aspnet core, I would prefer to have the ability to use standard middleware alongside ServiceStack if possible.

If you want to compress everything it’s more efficient to enable compression on the external webserver proxying requests to your .NET Core process (e.g. nginx/IIS) where the compression is efficiently done in native code.

You can compress all Service Responses for clients that support it by executing the [CompressResponse] attribute for all Service requests:

GlobalResponseFiltersAsync.Add((req, res, dto) => 
    new CompressResponseAttribute().ExecuteAsync(req, res, dto));

Also check out the Static File Compression for specifying which files to compress, i.e. you don’t want to compress any file types that include their own compression like images or videios.

Is there a way to prevent ServiceStack from compressing anything so this can be implemented elsewhere?

ServiceStack compression is opt-in, you need to use caching or compress attribute to enable compression.

But that is the problem. I want IIS or the middleware to compress, but I also want to use the [CacheResponse] attribute and other caching mechanisms in SS. Why do those have to return a compressed response - should that not be a global setting to configure?

Because the compressed response is what gets cached and written directly to the response stream, saving the CPU resources for anyone compressing the response, since it’s already compressed. The Content-Encoding HTTP Header indicates what the response was compressed which should also prevent anyone else from trying to compress an already compressed response.

Awesome, enabled dynamic compression and set it up properly in IIS and removed AspNet compression middleware. Thanks for the discussion Demis.

1 Like

Cool, one thing you want to watch out for with dynamicCompression is if you’re using Server Events as it will buffer and delay the events.