19

I have added the web.config entry to enable gzip compression based on this S/O answer Enable IIS7 gzip.

I then checked the Chrome Developer window while loading an ASPX page and saw the header in the response:

Cache-Control:private
Content-Encoding:gzip
Content-Length:3669
Content-Type:text/html; charset=utf-8
Date:Wed, 04 Mar 2015 00:46:05 GMT
Server:Microsoft-IIS/7.5
Vary:Accept-Encoding
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET

So that means it's "working", correct? But when looking for that header when making a Web API call, it is not present:

Cache-Control:no-cache
Content-Length:551
Content-Type:application/json; charset=utf-8
Date:Wed, 04 Mar 2015 00:53:05 GMT
Expires:-1
Pragma:no-cache
Server:Microsoft-IIS/7.5
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET

I have tried all kinds of different configurations (starting with the one recommended in the linked S/O answer above). Finally, in an act of desperation, I set it to this, which I thought would make it try to compress all requests (everything except */* commented out):

  <httpCompression directory="%SystemDrive%\inetpub\temp\IIS Temporary Compressed Files">
    <scheme name="gzip" dll="%Windir%\system32\inetsrv\gzip.dll"/>
    <dynamicTypes>
      <add mimeType="*/*" enabled="true"/>
      <!--<add mimeType="text/*" enabled="true"/>
      <add mimeType="message/*" enabled="true"/>
      <add mimeType="application/javascript" enabled="true"/>
      <add mimeType="application/json" enabled="true"/>-->
      <!--<add mimeType="*/*" enabled="false"/> -->
    </dynamicTypes>
    <staticTypes>
      <add mimeType="*/*" enabled="true"/>
      <!--<add mimeType="text/*" enabled="true"/>
      <add mimeType="message/*" enabled="true"/>
      <add mimeType="application/javascript" enabled="true"/>
      <add mimeType="application/json" enabled="true"/>-->
      <!-- add mimeType="*/*" enabled="false"/>-->
    </staticTypes>
  </httpCompression>
  <urlCompression doStaticCompression="true" doDynamicCompression="true"/>

What can be preventing the GZIP from being applied to my Web API methods?

Update

I have since tried both the NuGet Web API Compression package, and editing the applicationHost.config in both IIS Express 8.0 (Visual Studio) and a locally-installed IIS 7.5. All have yielded the same results: requests for other mime types like text/* work, but application/json refuses to be gzipped.

Community
  • 1
  • 1
FirstDivision
  • 980
  • 2
  • 11
  • 28

8 Answers8

11

Is the WebAPI behind a Firewall, Web Proxy, Virus Protection Suite? As mentioned in Even Faster Web Sites: Performance Best Practices for Web Developers By Steve Souders This could be stripping out the headers.

Paul
  • 1,435
  • 14
  • 32
  • No firewalls. I've tried everything on on both via localhost in IIS Express 8 (i.e. Visual Studio), and IIS 7.5 locally, and IIS 7.5 on a server on the same network. – FirstDivision Apr 24 '15 at 17:12
  • 2
    Ok, turns out I was wrong. On the same dev machine there is a full IIS installation that is running Application Request Routing which is acting as a reverse proxy to allow machines from outside the local environment to hit _that_ IIS, which will then forward the request down into the local IIS Express instance (which will not allow external connections). Even though I was doing _most_ of my testing against the local instance when trying to enable gzip, the routing entry from the full IIS was in the web.config (same directory). Removing that web.config entry brought the NuGet gzip to life. – FirstDivision Apr 30 '15 at 17:49
  • 4
    Thanks - for me it was ESET AntiVirus decompressing all responses internally. The solution was to disable the "web scanner" module. – NickG Aug 26 '16 at 13:30
5

According to ASP.NET Web API Compression (Ben Foster Blog) you have two options:

  1. Change your applicationHost.config and add

    to httpCompression -> dynamicTypes section.

  2. Use an delegating handler in your web api pipeline to handle the compression.
    e.g. Fabrik.Common or Microsoft ASP.NET Web API Compression Support

Stefan Ossendorf
  • 621
  • 5
  • 13
  • I've tried the applicationHost.config locally through IIS Express 8.0 and locally through IIS 7.5. I have not tried it on our dev server yet (IIS 7.5). I did bring in, configure, and deploy the NuGet package (locally and to the dev server). All have the same results. I have not tried the Fabrik solution yet, but I have a feeling it's nearly the same solution as the nuget package? – FirstDivision Apr 24 '15 at 17:15
  • I've not compared both, but I think the differnce is only between the implementation. So both should produce the same (compressed) output. – Stefan Ossendorf Apr 25 '15 at 08:41
5

Thanks to the 2 above solutions and other solutions elsewhere I figured a step by step explanation of how to get http compression working with Web API 2.2 might be beneficial as a few packages/namespaces have changed since the above posts.

1) Using nuget package manager console install the following;

Install-Package Microsoft.AspNet.WebApi.MessageHandlers.Compression

2) Inside WebApiConfig.cs add these usings;

using System.Net.Http.Extensions.Compression.Core.Compressors;
using Microsoft.AspNet.WebApi.Extensions.Compression.Server;

3) Inside WebApiConfig.cs add to the bottom of Register(HttpConfiguration config);

GlobalConfiguration.Configuration.MessageHandlers.Insert(0, new ServerCompressionHandler(new GZipCompressor(), new DeflateCompressor()));

4) Edit your web.config and inside system.webServer add;

<urlCompression doStaticCompression="true" doDynamicCompression="true" dynamicCompressionBeforeCache="true" />
<httpCompression>
    <dynamicTypes>
        <clear />
        <add enabled="true" mimeType="text/*" />
        <add enabled="true" mimeType="message/*" />
        <add enabled="true" mimeType="application/x-javascript" />
        <add enabled="true" mimeType="application/javascript" />
        <add enabled="true" mimeType="application/json" />
        <add enabled="false" mimeType="*/*" />
        <add enabled="true" mimeType="application/atom+xml" />
    </dynamicTypes>
    <staticTypes>
        <clear />
        <add enabled="true" mimeType="text/*" />
        <add enabled="true" mimeType="message/*" />
        <add enabled="true" mimeType="application/javascript" />
        <add enabled="true" mimeType="application/atom+xml" />
        <add enabled="true" mimeType="application/xaml+xml" />
        <add enabled="true" mimeType="application/json" />
        <add enabled="false" mimeType="*/*" />
    </staticTypes>
</httpCompression>

Worked first time on both local and an azure website so hopefully it works for you! Plus certainly no need to mess with applicationHost.config...

alv
  • 631
  • 6
  • 11
4

The problem you are seeing is because as the documentation states https://github.com/azzlack/Microsoft.AspNet.WebApi.MessageHandlers.Compression responses less than 860 bytes are NOT compressed, and your example show "Content-Length:551". Send some more data and it should work just fine.

Cine
  • 3,795
  • 23
  • 40
3

I think you have made all the homework in the server side, but the problem is in the request.

To allow the server to compress the response it's neccessary to inclue this header in the request:

Accept-Encoding: gzip, deflate

If you don't do it, no matter what you do on the server side, the response will never be compressed.

You don't specify which is your Web API client, but there is always a way to add headers in the request using the client API.

JotaBe
  • 34,736
  • 7
  • 85
  • 109
  • My main way I test is through the Web API Test client, so it's a jquery request under the hood. The Accept-Encoding header is there. Good idea though! – FirstDivision Apr 27 '15 at 21:31
3

I think @Peeticus was on the right track.

Here is what I did to make it work:

After running "Install-Package Microsoft.AspNet.WebApi.MessageHandlers.Compression" or adding it thru the GUI you need to update /App_Start/WebApiConfig.cs

The following additional using statements are required:

using Microsoft.AspNet.WebApi.MessageHandlers.Compression.Compressors;
using Microsoft.AspNet.WebApi.MessageHandlers.Compression;

Add the following inside the WebApiConfig.Register method:

GlobalConfiguration.Configuration.MessageHandlers.Insert(0, new ServerCompressionHandler(new GZipCompressor(), new DeflateCompressor()));

Next in the IISExpress applicationHost.config find the <httpCompression>'s <dynamicTypes> element and the following before the default <add mimeType="/" enabled="false" />

<add mimeType="application/json" enabled="true" />

Also in the applicationHost.config update <urlCompression /> to

<urlCompression doDynamicCompression="true" />
Dane W
  • 171
  • 1
  • 6
  • As an aside I tried to be smart and update '
    ' to allow me to make these changes in web.config but that didn't work for me. Additionally I did NOT need to add a separate entry for 'application/json; charset=utf-8'
    – Dane W Apr 30 '15 at 01:06
2

At first.

IIS Ignores WEB API Response compression because web api responses are of mime type

application/json; charset=utf-8

Default IIS Compression settings do not include this Mime type so they do not compress the response.

So your have to add this mime type to the <dynamicTypes> section

<add mimeType="application/json; charset=utf-8" enabled="true" />

(Or just to test it , as you did <add mimeType="*/*" enabled="true" />)

BUT

By default <httpCompression> Section is locked by IIS for settings from outside!!

So any settings you specify on your web.config will get ignored!

Unless you specify these settings on the applicationHost.config <httpCompression> section OR edit the <httpCompression> section to allow settingsfrom outside.

<section name="httpCompression" allowDefinition="MachineToApplication" overrideModeDefault="Allow" />
Anestis Kivranoglou
  • 6,398
  • 4
  • 38
  • 42
1

In your implementation of the NuGet package Microsoft.AspNet.WebApi.MessageHandlers.Compression, did you add the requisite line (below) to your App_Start\WebApiConfig.cs file? Note that is must be after all other message handlers in that same method, as per instructions on the package's home site.

GlobalConfiguration.Configuration.MessageHandlers.Insert(0, new ServerCompressionHandler(new GZipCompressor(), new DeflateCompressor()));

Here's a sample Register method from a WebApiConfig file that I used in a blog:

    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services

        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { echo = RouteParameter.Optional }
        );
        GlobalConfiguration.Configuration.MessageHandlers.Insert(0, new ServerCompressionHandler(new GZipCompressor(), new DeflateCompressor()));
    }

This is the blog post I mentioned: .Net Web API Compression

Peeticus
  • 43
  • 6