Compression (deflate) and HTML, CSS, JS Minification in ASP.NET

As I’ve already demonstrated, I like performance. So I cache and compress a lot. When I was put onto an ASP.NET project at work, I obviously wanted to optimize the site, so here’s what I did.

Taking some hints from Y! Slow, I decided I wanted to:

  • Get rid of all the MS AJAX/toolkit javascript, as we used jQuery instead
  • Combine all the javascript into one request
  • Combine all the CSS into one request
  • Minify the CSS
  • Minify the javascript
  • Minify the HTML
  • Deflate everything (gzip is slightly larger, and all modern browsers support deflate, so I just ignored gzip)

I followed the directions outlined at this site to override the ScriptManager and prevent it from including the Microsoft AJAX javascript. Removing uunsed code is always a good thing.

Combining the javascript was easy. Starting in ASP.NET 3.5 SP1, ASP.NET’s ScriptManager supports the CombineScript tag inside of it. That was easy.

Combining the CSS was not so easy, as there’s no such thing in ASP.NET as a “ScriptManager.” I had two options: make a CSS manager (and use it everywhere), or figure out another way. Never taking the easy route when there’s a more interesting (and more front end developer transparent) way, I decided to make a filter (implementer of IHttpModule) to find all the “<link>” tags in the page header and replace them with one “<link>” to a combined CSS handler (which I called “CssResource.axd” to parallel ScriptManager’s “ScriptResource.axd”). Then, in my IHttpHandler implementation which handles CssResource.axd, I read the querystring, grab the requested CSS files from the file system, combine them into one string, and return them. CSS combining done.

For minifying the CSS and Javascript, I used the C# version of YUI Compressor. I used the original (Java) YUI Compressor before, and had a great experience, so picking this version was a no-brainer. In my aforementioned filter, I intercept requests for “ScriptResource.axd” and “CssResource.axd,” apply YUI Compressor to the response content, cache the result (so I don’t need to minify every single request), then return.

I also minify inline (as in, mixed with HTML) CSS and Javascript. Also in my filter, if the return type is HTML, I scan for “<script src” and “<link rel=’stylesheet’ src=” and minify their contents. This minification does have to happen for every request to that page, unless that whole page is cached.

Finally, the last thing the filter does is check if the browser accepts deflate compression. If it does, the filter compresses the stream. In the case of “ScriptResource.axd” and “CssResource.axd” requests, the deflating is done before the response is cached, so requests for those resources don’t need to be re-deflated for every request (their content is static, unlike regular html requests, so caching the whole response is okay).

The initial (cache empty) page load was 780k before I started. When I had finished, the page load was only 234k – a 70% decrease.

You can download the code from this site. To use it, you need to modify your web.config.

<add type="CompressionModule" name="CompressionModule" /><!--This must be the last entry in the httpHandlers list-->
<add verb="GET,HEAD" path="CssResource.axd" validate="false" type="CssResourceHandler"/>

I cannot claim 100% credit for all of this work. I got many ideas from just browsing web search results, trying things out, and combining ideas from various sources. If I have not credited you, and I should have – I apologize, and will be happy to do. But I can say, that I did not just “copy and paste” this from anywhere – I’m confident that this work cannot be classified as a derived work of anything else. With that in mind, I release it into the public domain.

CC BY-SA 4.0 Compression (deflate) and HTML, CSS, JS Minification in ASP.NET by Craig Andrews is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

7 thoughts on “Compression (deflate) and HTML, CSS, JS Minification in ASP.NET

  1. Hey Craig,

    Wanting to give your code a try but the ZIP appears to be corrupted. Is it just me or does it need to be re-uploaded?


  2. @Zak Sorry about the slow response – you’re comment was marked as spam.

    The archive seems to be okay. I tested it on Windows and Ubuntu without issue. I hope downloading it again will solve your problem.

  3. Hmm, just got a chance to test this out. It works good but it’s actually breaking my Asp.Net AJAX and keps it from loading and finding my ScriptResource.axd files. I’d love to drop the toolkit, but for the time being it’s going to stay put. Any ideas on how to correct, or did you not see this issue? Oh and btw, it compresses my page source from 48k to 9k, crazy fast loading times, just wish it didnt break the toolkit.


  4. Awesome,

    This really helped me out. IIS7 seems to take care of most of these issues but the HTML minify was a real winner.

    My only feedback is StringComparison.OrdinalIgnoreCase is a better comparer, it is quicker.


  5. Nice job! I have only a strange problem, after having minimized the html, if I see the code, there is no character at the end of tag
    I see
    Why? Many thanks! 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.