Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET - Invalidate browser cache

I have a question related to cache invalidation techniques... I am trying to implement a mechanism for my website, that automatically invalidates browser cache (css, images...). I want to be able to programatically invalidate browser cache, whenever I update the website (change images or styles);

For example: for the current release, among others, the css and some of the images have changed. In this situation I want that after the update is finished, when a user performs a request to the website, his browser's cache to get automatically invalidated, thus forcing the re-download of the new images and styles. This should be done only for the client's first request... the following ones should be retrieved from cache (so setting the no-cache pragma is out of the question).

Here's what i've tried: in the BeginRequest event handler, I added the following lines:

Response.Cache.SetCacheability(HttpCacheability.ServerAndPrivate);
Response.Cache.SetETag("\"e111293b17594f1487d136ea7e9314ac\"");

this sets the ETag in the response headers. I figured that if I change this ETag at each release, and set it at each request, the cache will be invalidated, but it seems that it is not. I used Live HTTP headers to see the results and the ETAG is correctly set up for the response, but the css and images are still taken from cache.

Any ideas of how I could accomplish this, or if it can be accomplished at all?

like image 778
GeoXYZ Avatar asked Nov 26 '09 15:11

GeoXYZ


2 Answers

I have run into issues like this in the past. Unfortunately I couldn't find a really nice way to accomplish this so I had to come up with a workaround. I was only dealing with this issue for CSS files so I added an extra querystring parameter to every CSS reference, for example

 <link rel="stylesheet" type="text/css" 
       href="default.css?buildnumber=<%= Buildnumber %>" />

The build number gets incremented with each release so the browser was forced to go look for this new file. Not an ideal solution, but it worked without a hitch.

like image 71
Bob Avatar answered Sep 28 '22 07:09

Bob


For those who are seeking for a MVC5 solution:

Step1: Change the AssemblyInfo.cs file of the project to the following

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

Step 2: Create a class to get the current version info on your project:

     public class Versioner
        {
            public static Version GetVersion()
            {
                Assembly thisAssem = typeof(Versionador).Assembly;
                AssemblyName thisAssemName = thisAssem.GetName();
                Version vrs = thisAssemName.Version;
    
                return vrs;
            }
    


//Not really necessary, just if you need to show this info
            public static string GetDataBuild()
            {
                Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
                DateTime buildDate = new DateTime(2000, 1, 1).AddDays(version.Build).AddSeconds(version.Revision * 2);
                string displayableVersion = $"{version} ({buildDate})";
    
                return displayableVersion;
            }
        }

Step 3: Call the class methods in the views which needs cache auto-refresh on new builds.

    @{
    Version _ver = <MyProject>.Classes.Extensions.Versioner.GetVersion();
    }
//here, <MyProject>.Classes.Extensions is my path to the Versioner.cls class file, adjust it to your project's classes path

Step 4: Use the variable with the version string to append to your scripts or .css files

 <script src="~/js/index.js?v=@_ver"></script>
 <link href="/css/style.css?v=@_ver" rel="stylesheet" />
like image 39
Airton J. Colombini Avatar answered Sep 28 '22 07:09

Airton J. Colombini