It's an unfortunate reality that after updating an external CSS or JavaScript file referenced from a web page, not all browsers that have been to your site before will detect an updated file it has previously cached. When this happens, browsers are running outdated JS and applying old styles to your page elements.
One of the common workarounds for this situation that I've found quite effective is to append some value to the query string of the external file. So instead of the typical link (to a CSS file) in the Head section of your document,
<link href="styles.css" type="text/css" rel="stylesheet" />
You instead use a link with an arbitrary value following the actual file name:
<link href="styles.css?v=1" type="text/css" rel="stylesheet" />
Browsers cache the CSS file with an Id of "styles.css?v=1". If you update your CSS file, you can change the "v=1" to "v=2" in your HTML page and the browser treats styles.css?v=2 as a different file than styles.css?v=1. Since styles.css?v=2 isn't already cached, the browser will fetch the latest copy of styles.css from your web server. Constantly modifying (and trying to remember to modify) the query string value when I make changes to CSS and JS files has always been a manual task for me. Recently, however, I created a mechanism to automate this process.
The automated process appends the timestamp of the external file (CSS of JS) to the query string following the file's name that is sent to the browser. The file timestamp is stored in the .NET cache with a cache dependency to the actual file on the web server. Whenever I update the CSS or JS file, the timestamp is automatically removed from the cache and the next time a visitor arrives at the page and the timestamp is needed, the timestamp is retrieved and stored in cache. The purpose of the cache is to obviously reduce the amount of file I/O and overall time required in getting the page to the browser. I've fallen in love with this process as it's made my life easier!
The download link at the bottom of this post contains the code for a static GetFileWithVersion() function. The same function can be used for any external file that you want to prevent browsers from mistakenly hanging onto a copy of after you may have updated the file. At present, GetFileWithVersion returns a string value containing the filename and appended query string value. It's the caller's responsibility to add the necessary link or script tag to the head section of the page.
Example usage of the GetFileWithVersion() function with a CSS file:
string CssFileWithVersion = utils.GetFileWithVersion("MainCss", "~/styles.css");
System.Web.UI.HtmlControls.HtmlLink cssLink = new System.Web.UI.HtmlControls.HtmlLink();
cssLink.Href = CssFileWithVersion;
cssLink.Attributes.Add("type", "text/css");
cssLink.Attributes.Add("rel", "stylesheet");
this.Header.Controls.Add(cssLink);
Example usage of the GetFileWithVersion() function with a JavaScript file:
string JsKey = "MainJs";
if (!ClientScript.IsClientScriptIncludeRegistered(this.GetType(), JsKey))
{
string JsFileWithVersion = utils.GetFileWithVersion(JsKey, "~/tools.js");
ClientScript.RegisterClientScriptInclude(this.GetType(), JsKey, ResolveClientUrl(JsFileWithVersion));
}
I've been using the GetFileWithVersion() function from master pages and standalone pages for a few weeks now. Putting this type of mechanism in place is definitely a time saver and since implementing this, I personally haven't seen or heard of any issues with old CSS or JavaScript showing up.
Code Download (1.74 kb)