HTTP compression in ASP.NET 2.0

by Mads Kristensen 26. August 2006 06:00

The new System.IO.Compression namespace in .NET 2.0 makes it easy to implement HTTP compression without having to touch IIS. The best thing about it is that you no longer need any third party compression components, it’s all build directly into .NET Framework.

There are different ways to implement the compression but I think an HttpModule is the right choice for this feature. Let's create one and call it CompressionModule.

The CompressionModule must adhere to the following rules:

  • Support both GZip and Deflate compression
  • Only compress if the browser supports it
  • Simplest possible implementation

These rules are important to make sure that the compression will run smoothly in every situation.

The code

An HttpModule is a class that implements the IHttpModule interface and gives it direct access to the underlying HttpApplication. We have to implement the Init method and attach the Application.BeginRequest event and the event handler that will do the compression.

#region Using   using System; using System.Web; using System.IO.Compression;   #endregion   /// <summary> /// Compresses the output using standard gzip/deflate. /// </summary> public class CompressionModule : IHttpModule {     #region IHttpModule Members     void IHttpModule.Dispose()   {     // Nothing to dispose;   }     void IHttpModule.Init(HttpApplication context)   {     context.BeginRequest += new EventHandler(context_BeginRequest);   }     #endregion     #region Compression     private const string GZIP = "gzip";   private const string DEFLATE = "deflate";     void context_BeginRequest(object sender, EventArgs e)   {     HttpApplication app = sender as HttpApplication;     if (app.Request.RawUrl.Contains(".aspx"))     {       if (IsEncodingAccepted(GZIP))       {         app.Response.Filter = new GZipStream(app.Response.Filter, CompressionMode.Compress);         SetEncoding(GZIP);       }       else if (IsEncodingAccepted(DEFLATE))       {         app.Response.Filter = new DeflateStream(app.Response.Filter, CompressionMode.Compress);         SetEncoding(DEFLATE);       }     }

>

  }     /// <summary>   /// Checks the request headers to see if the specified   /// encoding is accepted by the client.   /// </summary>   private bool IsEncodingAccepted(string encoding)   {     return HttpContext.Current.Request.Headers["Accept-encoding"] != null && HttpContext.Current.Request.Headers["Accept-encoding"].Contains(encoding);   }     /// <summary>   /// Adds the specified encoding to the response headers.   /// </summary>   /// <param name="encoding"></param>   private void SetEncoding(string encoding)   {     HttpContext.Current.Response.AppendHeader("Content-encoding", encoding);   }     #endregion  

}

Implementation

Download the CompressionModule.cs file below and add it to the App_Code folder in the root of your website. Then add these lines to the web.config’s <system.web> section.

 <httpModules>    <add type="CompressionModule" name="CompressionModule" />  </httpModules>

That’s all you have to do to enable HTTP compression on an ASP.NET 2.0 website.

Download

 

CompressionModule.zip (0,75 KB) * Only $4.95/month ASP.NET & Windows 2008 + IIS 7 Hosting! FREE SQL Included

Tags:

ASP.NET

Comments

8/29/2006 8:06:37 PM #

 Damien Guard

There is (unfortunately) more to determining if an encoding is acceptable than checking it's presence within the Accept-encoding header.

First of all it might have a q-value of "0" which means it does not accept it - your filter here as-is would currently assume the opposite.  Also, if something such as gzip2 or gzipbasic came out again, you'd be detecting that as gzip.

www.w3.org/Protocols/rfc2616/rfc2616-sec14.html  has more details about the actual steps involved in checking the accept-encoding header correctly.

Otherwise looks promising Smile

[)amien

Damien Guard |

9/1/2006 4:03:45 PM #

 Jayaveer

Hi,
Can we use this for compresion of webservices, if so how to decompress ?
Thanks,
Jayaveer.B

Jayaveer |

9/23/2006 3:22:51 AM #

 michael

Dude, very awesome! Simple and easy to implement. Really handy for all the AJAX stuff too (a surprising amount of content goes back and forth with AJAX implementations).

The main modification I had to make is to exclude the WebResource.axd from compression (bad things happen if you don't).

Thanks again!

michael |

9/27/2006 2:41:43 AM #

 Jon Adams

I have implemented on my own some of the comments here. But I am still having a problem using GZIP on very small aspx pages. It sends data to the browser that apprently can't be uncompressed or something. I'm not sure why it is failing just on small output pages. And since you have to set the filter before the page is rendered, there is no way of telling how big the resultant output will be.

Suggestions?

Jon Adams |

11/8/2006 7:39:26 AM #

 William

I have just implemented your module on a site I work on. It does the job and is very easy to implement, however I am using an HTML Editor (CuteEditor) and that CMS module doesn't work when I activate the module.

Would you know how I can stop some specific directories like /HTMLEditor/ or /intranet/ from being GZipped?

Thanks

W

William |

11/8/2006 7:47:22 AM #

Mads Kristensen

William, that is very easy.
Replace this line:
"if (app.Request.RawUrl.Contains(".aspx"))"

with this one:
"if (app.Request.RawUrl.Contains(".aspx") && !app.Request.RawUrl.Contains("/folder/"))"

Replace "/folder/" with the name of the folder to exclude fom compression.

Mads Kristensen |

11/29/2006 9:14:11 AM #

Dave Transom

It's worth mentioning that if you want to use Page level Output Caching, adding the filter in the BeginRequest stage will first compress your page, then cache it, then when the cached version is served, the already compressed version will be compressed again. To avoid this behavior, apply the filter in the PreRequestHandlerExecute stage.

So instead of:
context.BeginRequest += new EventHandler(context_BeginRequest);

Use:
context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);

Where "context_PreRequestHandlerExecute" is the renamed "context_BeginRequest" method.

Cheers
Dave

Dave Transom |

1/8/2007 1:26:19 PM #

 Eddie Conner

The compression is woking in FireFox and Netscape 8 but doesnt seem to be working in IE 6.0.29. Is there something that has to be changed to work in IE6?

Eddie Conner |

2/17/2007 5:39:00 PM #

 Sayitfast

This is great stuff... thanks for sharing!!!

Sayitfast |

2/24/2007 11:48:17 AM #

 PohEe.com

How to exclude the WebResource.axd?
Set in WebConfig?

PohEe.com |

2/25/2007 7:56:19 PM #

 PohEe.com

My WebResource.axd still included into the compression. I gave up and try Blowely compression engine. You just have to follow the describe guide[pohee.com/2007/02/http-compression-in-aspnet-20/] to use it. It is a very good enigne but Mads Kristensen's engine also good if it enable us to exclude the WebResource.axd compression. cheers Smile

PohEe.com |

11/28/2007 12:41:53 PM #

Roops

Hi, Is it possible to exclude compression of one page from the entire application?
I have to extract an excel file from the datagrid and its getting compressed too. It shows junks characters in it.Kindly help.

Roops India |

4/24/2008 3:11:48 PM #

Roshawn

Nice code.  However, it doesn't seem to work with IIS7.  Why is that? Frown

Roshawn United States |

5/21/2008 12:39:53 AM #

Prashant Atal

I have the same problem and it does not work with IIS7.

Is there something special we need to do in the code>

Prashant Atal

Prashant Atal India |

9/25/2008 5:11:53 AM #

trackback

Using Cache And Compression For Performance

Using Cache And Compression For Performance

Tim-Stanley.com |

Comments are closed

About the slave

Mads Kristensen Mads Kristensen
Web developer at ZYB and founder of BlogEngine.NET. More...

LinkedIn ZYB Facebook Last.fm Twitter View Mads Kristensen's profile on Technorati

The Lounge

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2008