GZip compression with WCF hosted on IIS7
Asked Answered
T

8

24

Everyone, as far as I'm concerned the question is ansered in EDIT 2. Although it's only a partial solution to the IIS side of the problem, it's what I was looking for.


So I'm going to add my query to the small ocean of questions on the subject.

I'm trying to enable GZip compression on large soap responses from a WCF service. So far, I've followed instructions here and in a variety of other places to enable dynamic compression on IIS. Here's my dynamicTypes section from the applicationHost.config:

<dynamicTypes>
    <add mimeType="text/*" enabled="true" />
    <add mimeType="message/*" enabled="true" />
    <add mimeType="application/x-javascript" enabled="true" />
    <add mimeType="application/atom+xml" enabled="true" />
    <add mimeType="application/xaml+xml" enabled="true" />
    <add mimeType="application/xop+xml" enabled="true" />
    <add mimeType="application/soap+xml" enabled="true" />
    <add mimeType="*/*" enabled="false" />
</dynamicTypes>

And also:

<urlCompression doDynamicCompression="true" doStaticCompression="true" />

Though I'm not so clear on why that's needed.

Threw some extra mime-types in there just in case. I've implemented IClientMessageInspector to add Accept-Encoding: gzip, deflate to my client's HttpRequests. Here's an example of a request-header taken from fiddler:

POST http://[omitted]/TestMtomService/TextService.svc HTTP/1.1
Content-Type: application/soap+xml; charset=utf-8
Accept-Encoding: gzip, deflate
Host: [omitted]
Content-Length: 542
Expect: 100-continue

Now, this doesn't work. There's simply no compression happening, no matter what the size of the message (tried up to 1.5Mb). I've looked at this post, but have not run into an exception as he describes, so I haven't tried the CodeProject implementation that he proposes. Also I've seen a lot of other implementations that are supposed to get this to work, but cannot make sense of them (e.g., msdn's GZip encoder). Why would I need to implement the encoder, or the code-project solution? Shouldn't IIS take care of the compression?

So what else do I need to do to get this to work?

Joni

EDIT: I thought the WCF bindings might be worth posting, though I'm not sure if they're relevant (these are from client):

<system.serviceModel>
<bindings>
    <wsHttpBinding>
    <binding name="WsTextBinding" closeTimeout="00:01:00" openTimeout="00:01:00"
      receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false"
      transactionFlow="false" hostNameComparisonMode="StrongWildcard"
      maxBufferPoolSize="5000000" maxReceivedMessageSize="5000000"
      messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
      allowCookies="false">
      <readerQuotas maxDepth="32" maxStringContentLength="5000000"
        maxArrayLength="5000000" maxBytesPerRead="5000000" maxNameTableCharCount="5000000" />
      <reliableSession ordered="true" inactivityTimeout="00:10:00"
        enabled="false" />
      <security mode="None">
        <transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
        <message clientCredentialType="None" negotiateServiceCredential="false"
          algorithmSuite="Default" establishSecurityContext="false" />
      </security>
<client>
  <endpoint address="http://[omitted]/TestMtomService/TextService.svc"
   binding="wsHttpBinding" bindingConfiguration="WsTextBinding" behaviorConfiguration="GzipCompressionBehavior"
   contract="TestMtomModel.ICustomerService" name="WsTextEndpoint">
  </endpoint>
</client>
<behaviors>
  <endpointBehaviors>
    <behavior name="GzipCompressionBehavior">
      <gzipCompression />
    </behavior>
  </endpointBehaviors>
</behaviors>
<extensions>
  <behaviorExtensions>
    <add name="gzipCompression"
         type="TestMtomModel.Behavior.GzipCompressionBehaviorExtensionElement, TestMtomModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  </behaviorExtensions>
</extensions>
    </binding>
  </wsHttpBinding>
</bindings>

EDIT 2: Well for anyone else in this mysterious situation, I have a partial solution. I.e., I've gotten IIS7 to at least compress the soap messages from the service (though I now get an exception on the client, but for that there have been several solutions posted). The problem was that the DynamicCompressionModule was not installed on my server. "Installing" it actually, for me, meant simply adding this line to applicationHost.config's section:

<add name="DynamicCompressionModule" image="%windir%\System32\inetsrv\compdyn.dll" />

(Assuming the dll exists in that directory, which in my case it did.) And then adding the module via IIS7's Modules section for the website or server.

Triturable answered 26/4, 2010 at 11:58 Comment(1)
Probably a dumb question, but it tricked me up for a while - how do you know that the compression is not happening? If it's because you're not seeing it in Fiddler, be aware that Fiddler will automatically decompress unless you tell it not to.Wicket
S
14

Try adding 'application/soap+xml; charset=utf-8' as dynamic type in applicationHost. Adding this charset part helped me to enable compression for some JSON responses from my http handler.

Serles answered 16/6, 2010 at 5:34 Comment(3)
+1 - this is the answer - I had to do exactly this to make compression work WITHOUT using any additional components whatsoever. That is, assuming the dynamic compression module is switched on and installed :)Serranid
You might need to enable the same mime type multiple times, as Microsoft tends to do string comparisons rather than content comparisons. (i.e. application/soap+xml;charset=utf-8, application/soap+xml;charset=ISO-8895-1, application/soap+xml; charset=ISO-8895-1)Encourage
Enabling dynamic compression (gzip, deflate) for WCF Data Feeds, OData and other custom services in IIS7 --- hanselman.com/blog/…Imogen
A
10

This is basically the same answer as @marko - with detailed steps. This is a frustrating topic every time I revisit it so I wanted to outline everything I need to do to get it working.

  • First things first you'll want to be using .NET 4 on IIS7. This is because it wasn't until .NET 4 that WCF was capable of automatically decompressing gzip streams. The details of this are descibed in 'Whats new in WCF 4' (some useful comments in feedback).

    We’ve made that easier when using HTTP by allowing the client to automatically negotiate using gzip or deflate compressed streams and then automatically decompress them.

  • Second, make sure you have enabled the dynamic compression module in IIS. You may need to go to 'Programs and Features' to install it. Be sure that you have it enabled for the web application in question - as it is not a global setting.

  • Now WPF uses the MIME type application/soap+xml; charset=utf-8 for HTTP transmission (at least with wsHttpBinding it does). By default this is NOT classed as a dynamic type so it needs to be added to the applicationHost.config file.

    Just edit this file ON THE SERVER: C:\Windows\System32\Inetsrv\Config\applicationHost.config

    In the <dynamicTypes> node add the following line (BEFORE THE / LINE) :

    <add mimeType="application/soap+xml; charset=utf-8" enabled="true" />
    

    More on the applicationHost.config file

  • Restart IIS

You should now have compressed data - which can be verified in Fiddler.

Audrit answered 14/9, 2010 at 3:29 Comment(2)
This post is the juice. Thanks a ton! (Amazing how the right post gets you there.... and the others just confuse!)Cotterell
Sorry for dumb question but why cannot be this mimeType settings in application's web.config? I have tried this, does not work. But why? It is not suitable for me edit applicationhost.config on every single server, where is my application hosted.Tavel
M
1

I've been struggling with this too and couldn't get it to work with my .svc even though it was fine with .aspx files in the same app. It turns out that it only works with basicHttpBinding and not wsHttpBinding or a binary encoded customBinding. This is fine for me as the compression factor outwieghs the benefit of the binary encoder (which reduces message size by quite a lot but not the factor of 10 that the compression gives).

Meliorism answered 2/3, 2011 at 13:28 Comment(1)
Please see my answer on why it works for basicHttpBinding and does not for wsHttpBinding. There is a way!Hormone
P
0

Best bet is to evaluate the specific mime type you are having trouble with (e.g. Fiddler) and ensure that is incorporated in applicationHost.config. If compression is installed and configured correctly, failed request tracing will let you know that compression was not performed with a "NO_MATCHING_CONTENT_TYPE" disposition.

Paladin answered 16/6, 2010 at 17:15 Comment(1)
Thanks for the answers guys. However, the IIS side of the problem was already solved. Please read EDIT 2 in the original post. I would have marked the question as the answer if I could, even though it's just a partial solution to the problem, but I can't.Triturable
M
0

The mime type is most likely Application/octet-stream

Meantime answered 26/8, 2011 at 12:20 Comment(0)
H
0

Just for someone else who may look in the future. We upgraded to Windows 2012 server and IIS 8. The old config compression mimetypes which worked for IIS 7 did not work for IIS 8.

So, I tried a couple of suggestions here, but nothing worked. I ended up just adding this to httpcompression dynamictypes: multipart/* and then gzip compression was working again.

Hope this helps someone else.

Hands answered 19/2, 2015 at 21:54 Comment(0)
H
0

A lot of people are struggling with enabling IIS level compression for WCF Services. Mainly people are struggling with wsHttpBinding, where basicHttpBinding compresses out of the box if dynamic compression is enabled in IIS. I am not going to go into how to enable dynamic compression because it's covered in many different posts, just search for "iis compression application/soap+xml". As previously stated, if you've configured everything properly you should be able to see WCF responses compressed with Content-Encoding: gzip in response header. I suggest using Fiddler to track your request/response. This was my (any many others) experience with basicHttpBinding. The question then becomes why does it not work with wsHttpBinding? Undoubtedly you've already read that it's because the Content-Type is different between those two bindings. basicHttpBinding uses Content-Type: text/xml; charset=utf-8 where wsHttpBinding uses Content-Type: application/soap+xml; charset=utf-8. The former is covered by the default IIS applicationHost.config setting under dynamicTypes. The latter is not. You probably read that you need to add this additional mimeType and restart IIS to fix this. This works for some people, however it does not for many. Some declare that it's simply not compatible with wsHttpBinding. Here is the problem. There are potentially two applicationHost.config files:

C:\Windows\System32\inetsrv\config
C:\Windows\SysWOW64\inetsrv\Config

System32 is the 64bit one, and is the one used by your installation of IIS. This is also the one you've modified to add the additional mimeType to, or so you thought!

cannot manually edit applicationhost.config - MUST READ

As it turns out, if you use a 32bit application such as Notepad++, what you end up modifying is the file in the SysWOW64 folder. This is completely transparent to you. If you use regular Notepad application you'll notice that the mimeType you've added is actually not in the file that is located in the System32 folder, it was magically added to the SysWOW64 folder, even though you've never actually browsed to that folder to begin with. Hopefully this saves you many hours of grief.

Hormone answered 16/9, 2015 at 14:57 Comment(0)
S
0

If anyone ever stumble upon this when hosting in Azure as WebApp, you can configure the applicationHost.config using an extension called "IIS Manager" using the azure portal under "Extensions". More info on the extension itself https://github.com/shibayan/IISManager

Sniperscope answered 5/10, 2017 at 9:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.