Auto-versioning in ASP.NET MVC for CSS / JS Files?

Tom picture Tom · Jan 30, 2011 · Viewed 13.8k times · Source

I have read lots of article on how to auto-version your CSS/JS files - but none of these really provide an elegant way to do this in ASP.NET MVC.

This link - How to force browser to reload cached CSS/JS files? - provides a solution for Apache - but I'm a little confused how this could be implemented via ASP.NET MVC ?

Would anyone be able to provide some advice how to do this on IIS7 and ASP.NET MVC - so that CSS/JS files automatically have a version number inserted in the URL without changing the location of the file ?

That is, so links come out link this etc presumably using the URL Rewrite or ?

<link rel="stylesheet" href="/css/structure.1194900443.css" type="text/css" />
<script type="text/javascript" src="/scripts/prototype.1197993206.js"></script>

Thx

Answer

Nathan Anderson picture Nathan Anderson · Jan 30, 2011

When faced with this problem I wrote a series of wrapper functions around the UrlHelper's Content method:

EDIT:

Following the discussions in the comments below I updated this code:

public static class UrlHelperExtensions
{
    private readonly static string _version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();

    private static string GetAssetsRoot()
    {
        string root = ConfigurationManager.AppSettings["AssetsRoot"];
        return root.IsNullOrEmpty() ? "~" : root;
    }

    public static string Image(this UrlHelper helper, string fileName)
    {
        return helper.Content(string.Format("{0}/v{2}/assets/img/{1}", GetAssetsRoot(), fileName, _version));
    }

    public static string Asset(this UrlHelper helper, string fileName)
    {
        return helper.Content(string.Format("{0}/v{2}/assets/{1}", GetAssetsRoot(), fileName, _version));
    }

    public static string Stylesheet(this UrlHelper helper, string fileName)
    {
        return helper.Content(string.Format("{0}/v{2}/assets/css/{1}", GetAssetsRoot(), fileName, _version));
    }

    public static string Script(this UrlHelper helper, string fileName)
    {
        return helper.Content(string.Format("{0}/v{2}/assets/js/{1}", GetAssetsRoot(), fileName, _version));
    }
}

Using these functions in conjunction with the following rewrite rule should work:

<rewrite>
  <rules>
    <rule name="Rewrite assets">
      <match url="^v(.*?)/assets/(.*?)" />
      <action type="Rewrite" url="/assets/{R:2}" />
    </rule>
  </rules>
</rewrite>

This article discusses how to create rewrite rules on IIS7.

This code uses the version number of the current assembly as a query string parameter on the file path's it emits. When I do an update to the site and the build number increments, so does the querystring parameter on the file, and so the user agent will re-download the file.