Christmas CSS and CDN fun

Ah yes. Back to the (semi) technical topics.

On the site we are working on, we serve everything except the HTML (via Umbraco) from a CDN. Littered throughout the code and references like:

{{codeclock}}

" /> {{/codeblock}}

.. but for CSS, JS and any images we have. The WrapUrl call just checks to see if we are using a CDN (we don't on dev), and puts the URL prefix (http://cdn.com/) and a suffix based on the time or fixed value at the end. So we started with

{{codeblock}}
/css/base.css
{{/codeblock}}

and on dev, we still have that. But on live, we have

{{codeblock}}
http://cdn.com/css/base.css?0115
{{/codeblock}}

the 0115 is a rolling value, which is used to cache-bust evey 15 mins (normally you'd do it on roll out, but we have users/editors editing css files on the live site, so we need to be able to invalidate on a regular basis, without rolling out again)

While this is trivial in ASPX-generated pages (we use Umbraco, so it's all ASPX masterpages and Razor macros), it's a lot harder in a .css file, as these files are not normally processed.

The solution, which I thought was going to be way, WAY too slow to use on a high traffic site, was to use a HTTP Handler to intercept *.css and rewrite it on the fly. It turns out that the rewrite on a reasonable sized CSS file is around 0ms

Seriously. I had to double check the stopwatch with a Thread.Sleep(500); to make sure it was working.

On the way thru, we can hold the results in cache (so we dont even need to do the 0ms of processing again until it expires), and serve up a nice cache-busting CSS file.

GitHub Gist: CSSRewiteHandler.cs

Next steps are to add CSS minification and maybe do the same for Javascript.

All very easy - in the end - and very, very fast. No chance I'm rolling this out the day before I go away on holiday tho!

Nic Wise

Nic Wise

Auckland, NZ