Tuesday, October 29, 2013

Enforcing JavaScript and CSS file refreshes on your ASP.NET website

A few years ago, I was part of a team that rolled out a website as part of a very large project.  The rollout on all aspects went reasonably well (except for one issue with a rather large page size, but we fixed that rather quickly).  One issue we had at launch however were some issues with existing users logging in for the first time.  Due to some funky logic we had in some JavaScript on our pages, some users were getting invalid error messages.  The bug was quickly identified and we rolled out the fix within an hour.  However, many of our users continued to have issues for hours after the fact.  The culprit was file caching.  In particular, our "login.js" file or whatever it was called was pushed to the web server, but web browsers were finding an existing file cached locally on the PC and were failing to download an updated version.
To force the new file to download, we went through all of our code, found references to all of our JS files (just to be safe) and appended a fake querystring value.  So our new code read as:
login.js?x=123

The querystring value can be arbitrary, just its presence gives the file a new name, and causes the web browser to detect a change and re-download the file, ignoring the cache.  However, now THIS file is now cached for some time, as all future references to login.js?x=123 will refer to the local copy.

So what if you want control over this programmatically?  Well, we have a few options.
The most basic method to handle this is to do what we did above, only add a value to your web config.  For example, add a configuration key called "CacheBuster".  In the ASP.NET world, it looks like this:
<add key="CacheBuster" value="X1235"/>
Now, you can refer to that value in our ASPX Markup, like so:
<script src="login.js?CacheBuster=<%=ConfigurationManager.AppSettings("CacheBuster")%>"></script>
This works for CSS files as well:
<link href="styles.css?CacheBuster=<%=ConfigurationManager.AppSettings("CacheBuster")%>" rel="stylesheet" />

See what we're doing there?  We're just referencing some value in our config file and appending it to our JS file reference.  Now, all references to the file will include our CacheBuster value.  So perhaps you are promoting a new website build and want to ensure that your users pull down the most current version of your JS or CSS files, you can just update the value in your config before deploying, and once the CacheBuster value has changed, it will ensure that all returning visitors get a new copy of your files.
Of course, we can do this from a timing perspective too.  Perhaps you want your users to pull a new file daily?  Just user the DateTime properties to create a unique value for that time period:
<script src="login.js?x=<%=DateTime.Now.Month.ToString() + DateTime.Now.Day.ToString + DateTime.Now.Year.ToString()%>"></script>

This means that accessing the webpage today would provide "login.js?x=10292013", while accessing it tomorrow would result in login.js?x=10302013".  From this perspective, you have incredible flexibility.  You can use "Ticks" if you really wanted to to ensure that your users always pull the most current file (while also increasing all web traffic, of course).  Or, you can combine both methods listed above, giving a CacheBuster value along with a DateTime MMDDYYYY value, ensuring that you have flexibility on updating all cached copies of your JS and CSS files daily and\or whenever you promote a new build.
Hope this helps!

No comments:

Post a Comment