Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to include static content with version info

Tags:

asp.net-mvc

I am having trouble with my static content being cached on the client (by static I mean js,css,jpeg,gif, etc). (and by client I mean its my development machine most of the time).

As a result, page is either throwing a script error, or not displaying correctly. I am not a Rails developer but I read a few books about it back in time. One thing I remember well is that it appends some magic version number to the end of the included file, so it becomes

<script src="~/Scripts/Invoice.js?201112091712" type="text/javascript"></script>

and if you modify that content file it generates a new version number, so it generates a different include statement, as a result, client thinks it is a new content, and it loads it without checking its cache.

Does asp.net-mvc 3 & IIS 7 support this, or do you know any tools that mimic this behaviour?

Thanks, Hazım

like image 799
hazimdikenli Avatar asked Sep 11 '25 20:09

hazimdikenli


2 Answers

I have this done already in one of my projects, feel free to use my helpers if you like them :

public static class VersionedContentExtensions
{
    public static MvcHtmlString VersionedScript(this HtmlHelper html, string file)
    {
        return VersionedContent(html, "<script src=\"{0}\" type=\"text/javascript\"></script>", file);                     
    }

    public static MvcHtmlString VersionedStyle(this HtmlHelper html, string file)
    {
        return VersionedContent(html, "<link href=\"{0}\" rel=\"stylesheet\" type=\"text/css\">", file);
    }

    private static MvcHtmlString VersionedContent(this HtmlHelper html, string template, string file)
    {
        string hash = HttpContext.Current.Application["VersionedContentHash_" + file] as string;
        if (hash == null)
        {
            string filename = HttpContext.Current.Server.MapPath(file);
            hash = GetMD5HashFromFile(filename);
            HttpContext.Current.Application["VersionedContentHash_" + file] = hash;
        }

        return MvcHtmlString.Create(string.Format(template, file + "?v=" + hash));
    }

    private static string GetMD5HashFromFile(string fileName)
    {
        FileStream file = new FileStream(fileName, FileMode.Open);
        MD5 md5 = new MD5CryptoServiceProvider();
        byte[] retVal = md5.ComputeHash(file);
        file.Close();

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < retVal.Length; i++)
        {
            sb.Append(retVal[i].ToString("x2"));
        }
        return sb.ToString();
    }
}

use them like this :

@Html.VersionedScript("/Scripts/sccat.core.js")
like image 106
rouen Avatar answered Sep 13 '25 23:09

rouen


I did something like this:

<script src="<%= GenerateScriptUrl("~/Scripts/Invoide.js") %>"></script>

In GenerateScriptUrl method, I write the content of the file, calculate the md5 value then get the url with version number. The url would be cached so it will be calculated twice. I also create an handler (not exposed to the user) to clear the cache. So the process doesn't need to be restarted when the file content is changed.

You can also get the version number with the last modified or thing. You can even monitor the file's change by FileSystemWatcher, etc.

Hope it helps.

like image 30
Jeffrey Zhao Avatar answered Sep 14 '25 00:09

Jeffrey Zhao