user1754675
user1754675

Reputation: 897

How to Ensure Latest Javascript & CSS in Browser Cache in ASP.NET MVC

I would like to ensure that latest version of js & css are in client browser cache. I have followed this link (http://blog.robvolk.com/2009/04/ensure-latest-javascript-css-in-browser.html?showComment=1354714427404#c5850523542624593865)

The problem I am not getting new hash-code on every build. I even try to clean and rebuild it does have the same hash-code.

I would appreciate if someone could advise how can I handle the browser cache.

Thanks

Upvotes: 0

Views: 1500

Answers (2)

Richard Varno
Richard Varno

Reputation: 547

UPDATE: The previous version did not work on Azure, I have simplified and corrected below. (Note, for this to work in development mode with IIS Express, you will need to install URL Rewrite 2.0 from Microsoft http://www.iis.net/downloads/microsoft/url-rewrite - it uses the WebPi installer, make sure to close Visual Studio first)

I fought with it for a couple of days and ended up rolling my own. (see link below for full explanation) You basically Auto-increment the assembly version every time the project is built, and use that number for a routed static file on the specific resources you would like to keep refreshed. (so something.js is included as something.v1234.js with 1234 automatically changing every time the project is built) - I also added some additional functionality to ensure that .min.js files are used in production and regular.js files are used when debugging (I am using WebGrease to automate the minify process) One nice thing about this solution is that it works in local / dev mode as well as production. (I am using Visual Studio 2015 / Net 4.6, but I believe this will work in earlier versions as well.

To implement, you can follow the following steps: (I know this is an old post, but I ran across it while developing a solution):

How to do it: Auto-increment the assembly version every time the project is built, and use that number for a routed static file on the specific resources you would like to keep refreshed. (so something.js is included as something.v1234.js with 1234 automatically changing every time the project is built) - I also added some additional functionality to ensure that .min.js files are used in production and regular.js files are used when debugging (I am using WebGrease to automate the minify process) One nice thing about this solution is that it works in local / dev mode as well as production. (I am using Visual Studio 2015 / Net 4.6, but I believe this will work in earlier versions as well.

Step 1: Enable auto-increment on the assembly when built In the AssemblyInfo.cs file (found under the "properties" section of your project change the following lines:

[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

to

[assembly: AssemblyVersion("1.0.*")]
//[assembly: AssemblyFileVersion("1.0.0.0")]

Step 2: Set up url rewrite in web.config for files with embedded version slugs (see step 3)

In web.config (the main one for the project) add the following rules in the <system.webServer> section I put it directly after the </httpProtocol> end tag.

<rewrite>
  <rules>
    <rule name="static-autoversion">
      <match url="^(.*)([.]v[0-9]+)([.](js|css))$" />
      <action type="Rewrite" url="{R:1}{R:3}" />
    </rule>
    <rule name="static-autoversion-min">
      <match url="^(.*)([.]v[0-9]+)([.]min[.](js|css))$" />
      <action type="Rewrite" url="{R:1}{R:3}" />
    </rule>
  </rules>
</rewrite>

Step 3: Setup Application Variables to read your current assembly version and create version slugs in your js and css files.

in Global.asax.cs (found in the root of the project) add the following code to protected void Application_Start() (after the Register lines)

            // setup application variables to write versions in razor (including .min extension when not debugging)
            string addMin = ".min";
            if (System.Diagnostics.Debugger.IsAttached) { addMin = ""; }  // don't use minified files when executing locally
            Application["JSVer"] = "v" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString().Replace('.','0') + addMin + ".js";
            Application["CSSVer"] = "v" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString().Replace('.', '0') + addMin + ".css";

Step 4: Change src links in Razor views using the application variables we set up in Global.asax.cs

@HttpContext.Current.Application["CSSVer"]
@HttpContext.Current.Application["JSVer"]

For example, in my _Layout.cshtml, in my head section, I have the following block of code for stylesheets:

<!-- Load all stylesheets -->
<link rel='stylesheet' href='https://fontastic.s3.amazonaws.com/8NNKTYdfdJLQS3D4kHqhLT/icons.css' />
<link rel='stylesheet' href='/Content/css/[email protected]["CSSVer"]' />
<link rel='stylesheet' media='(min-width: 700px)' href='/Content/css/[email protected]["CSSVer"]' />
<link rel='stylesheet' media='(min-width: 700px)' href='/Content/css/[email protected]["CSSVer"]' />
@RenderSection("PageCSS", required: false)

A couple things to notice here: 1) there is no extension on the file. 2) there is no .min either. Both of these are handled by the code in Global.asax.cs

Likewise, (also in _Layout.cs) in my javascript section: I have the following code:

<script src="~/Scripts/all3bnd100.min.js" type="text/javascript"></script>
<script src="~/Scripts/[email protected]["JSVer"]" type="text/javascript"></script>
@RenderSection("scripts", required: false)

The first file is a bundle of all my 3rd party libraries I've created manually with WebGrease. If I add or change any of the files in the bundle (which is rare) then I manually rename the file to all3bnd101.min.js, all3bnd102.min.js, etc... This file does not match the rewrite handler, so will remain cached on the client browser until you manually re-bundle / change the name.

The second file is ui.js (which will be written as ui.v12345123.js or ui.v12345123.min.js depending on if you are running in debug mode or not) This will be handled / rewritten. (you can set a breakpoint in Application_OnBeginRequest of Global.asax.cs to watch it work)

Full discussion on this at: Simplified Auto-Versioning of Javascript / CSS in ASP.NET MVC 5 to stop caching issues (works in Azure and Locally) With or Without URL Rewrite (including a way do it WITHOUT URL Rewrite)

Upvotes: 0

Lukas Kabrt
Lukas Kabrt

Reputation: 5489

I would suggest using bundling and minification of scripts and stylesheets. It is a new feature introduced together with MVC 4, but it seems, that someone was able to make it work with even MVC3 - ASP.NET MVC4 bundling in ASP.NET MVC3

ASP.NET Optimization uses similar approach as your solution - it appends a hash to the URL of script/style, but this hash is based on the content of the js/css file, not on an instance of the application assembly.

note: the blogpost by Jef Claes uses Microsoft.Web.Optimization package, that was replaced by Microsoft.AspNet.Web.Optimization, but I believe, it will work even with the Microsoft.AspNet.Web.Optimization package.

Upvotes: 1

Related Questions