Alexander Beletsky's development blog

My profession is engineering

Prevention of JS/CSS content to be cached

To do not waste a time in pauses between AgileBaseCamp talks I’ve created an utility that I wish to have, but had not time to do. It is very simple and solves caching issue for CSS and JS that we all suffered many times. Because every modern browsers try to cache static content, to make site rendering faster, we having trap then CSS or JS is being updated, but after deployment on production customers still see no results, because they use previous versions of files.

Classical way

Classical way of solving the issue is to add version info to content url and update it after each production update.

<link rel="stylesheet" href="Content/public.css?v=123" type="text/css" media="all" />
<script src="Scripts/script.js?v=123" type="text/javascript"></script>

The problem is that you have to remember to update version manually, before each deployment to production. That was something I was doing a lot and now decieded to automate it.

Better way

Idea is very simple, create a helper that would use version from assembly and append version to resource. Now, in markup I wrote:

<link rel="stylesheet" href="@Url.ContentWithVersion("~/Content/public.css")" type="text/css" media="all" />
<script src="@Url.ContentWithVersion("~/Scripts/script.js")" type="text/javascript"></script>

Code

namespace Web.Helpers.Extensions
{
    public static class UrlContentWithVersionExtension
    {
        private static string _currentAssemblyVersion;

        public static string ContentWithVersion(this UrlHelper helper, string path)
        {
            var contentPath = helper.Content(path);
            var assemblyVersionString = GetAssemblyVersionString();

            return string.Format("{0}?ver={1}", contentPath, assemblyVersionString);
        }

        private static string GetAssemblyVersionString()
        {
            if (_currentAssemblyVersion == null)
            {
                var currentAssemblyVersion = Assembly.GetExecutingAssembly().GetName().Version;
                _currentAssemblyVersion = currentAssemblyVersion.ToString().Replace(".", "");
            }

            return _currentAssemblyVersion;
        }
    }
}

And don’t forget that each page that uses the extension method, should include this namespace:

<!-- For MVC2 -->
<%@Import Namespace="Web.Helpers.Extensions" %>

<!-- For MVC3 (Razor) -->
@using Web.Helpers.Extensions

Example of usage

As always all code is on github, so extension itself is here. And commit there I integrated changes is here (would be useful to review, before your actual changes).