This post discusses an efficient way to compress content served by the ASP.NET output cache. In .NET Framework v2.0 SP1, included with Windows Server 2008, the ASP.NET Output Cache includes a new feature that allows cached responses to vary by the response's Content-Encoding header. And IIS 7.0 has efficient compression algorithms for gzip and deflate. Put the two together, and you can efficiently compress responses once, and serve them from the cache many times.
Here's how you can do this on Windows Server 2008:
1. If you haven't already, install the Dynamic Content Compression role for IIS 7.0 using the Server Manager.
2. Step 1 will add the <httpCompression> configuration section to applicationHost.config. Note that only gzip compression is supported by default. However, deflate is also implemented in gzip.dll, so if you add the following to the <httpCompression> configuration section, you'll also have deflate enabled:
<scheme name="deflate" dll="%Windir%\system32\inetsrv\gzip.dll" />
3. Create an application with an ASPX page like the one below. This example page will cache at most 3 responses, one that is gzip compressed, one deflate compressed, and one that is a normal (uncompressed) response.
<%@ Page language="C#" %><%@ OutputCache duration="600" varyByParam="None" varyByContentEncoding="gzip;deflate" %> <script runat="server"> void Page_Load() { Request.ServerVariables["IIS_EnableDynamicCompression"] = "1"; Response.Write(DateTime.Now); }</script>
<%@ Page language="C#" %><%@ OutputCache duration="600" varyByParam="None" varyByContentEncoding="gzip;deflate" %>
<script runat="server"> void Page_Load() { Request.ServerVariables["IIS_EnableDynamicCompression"] = "1"; Response.Write(DateTime.Now); }</script>
4. You must enable the IIS 7.0 "dynamic compression before cache" feature. You can do this by adding the following to your application's web.config file.
<system.webServer> <urlCompression doDynamicCompression="false" dynamicCompressionBeforeCache="true" /></system.webServer>
Note that in Step 4, doDynamicCompression="false". If you set this to "true", all responses will be compressed. That is, pages that are not using the output cache, as well as pages that are using the output cache (but may not be using varyByContentEncoding) will be compressed. Our example sets doDynamicCompression to "false" in configuration, but then uses the server variable "IIS_EnableDynamicCompression" to enable it for a specific page. Alternatively, you could use configuration and <location path=""> to limit the scope of compression.
So how does this work? When a request is sent to the server, it may or may not include an Accept-Encoding header, indicating one or more acceptable encodings. For example, Internet Explorer sends "Accept-Encoding: gzip, deflate". When the ASP.NET Output Cache receives the request, if the page is using the VaryByContentEncoding feature, ASP.NET will check if any of the encodings specified by VaryByContentEncoding match the request's Accept-Encoding header. If there is a match, ASP.NET will see if that response is in the cache and serve it. If it's not cached, ASP.NET will render the response and the IIS 7.0 DynamicCompressionModule, which runs during RQ_RELEASE_REQUEST_STATE, will encode the response according to the request's Accept-Encoding header, and it will set the response's Content-Encoding header. For the example request, the response header will be set to "Content-Encoding: gzip". When the ASP.NET OutputCacheModule runs during RQ_UPDATE_REQUEST_CACHE, it will check to see if the Content-Encoding header has been set, and if specified in VaryByContentEncoding, it will cache the response according to that encoding. If the Content-Encoding is not set, the response can be cached as the identity.
This ASP.NET Output Cache feature can be used via the <%@ OutputCache varyByContentEncoding= %> page directive, programmatically via HttpCachePolicy.VaryByContentEncodings, or via configuration outputCacheProfiles><add varyByContentEncoding=””></outputCacheProfiles>.
Here are a few of the implementation details:
Regards,Thomas