force browsers to get latest js and css files in asp.net application

118,779

Solution 1

I solved this by tacking a last modified timestamp as a query parameter to the scripts.

I did this with an extension method, and using it in my CSHTML files. Note: this implementation caches the timestamp for 1 minute so we don't thrash the disk quite so much.

Here is the extension method:

public static class JavascriptExtension {
    public static MvcHtmlString IncludeVersionedJs(this HtmlHelper helper, string filename) {
        string version = GetVersion(helper, filename);
        return MvcHtmlString.Create("<script type='text/javascript' src='" + filename + version + "'></script>");
    }

    private static string GetVersion(this HtmlHelper helper, string filename)
    {
        var context = helper.ViewContext.RequestContext.HttpContext;

        if (context.Cache[filename] == null)
        {
            var physicalPath = context.Server.MapPath(filename);
            var version = $"?v={new System.IO.FileInfo(physicalPath).LastWriteTime.ToString("MMddHHmmss")}";
            context.Cache.Add(filename, version, null,
              DateTime.Now.AddMinutes(5), TimeSpan.Zero,
              CacheItemPriority.Normal, null);
            return version;
        }
        else
        {
            return context.Cache[filename] as string;
        }
    }
}

And then in the CSHTML page:

 @Html.IncludeVersionedJs("/MyJavascriptFile.js")

In the rendered HTML, this appears as:

 <script type='text/javascript' src='/MyJavascriptFile.js?20111129120000'></script>

Solution 2

In ASP.NET Core (MVC 6) this works out of the box via the asp-append-version tag helper:

<script src="scripts/myjavascript.js" asp-append-version="true"></script>
<link href="styles/mystyle.css rel="stylesheet" asp-append-version="true" />

Solution 3

Your solution works. It is quite popular in fact.

Even Stack Overflow uses a similar method:

<link rel="stylesheet" href="http://sstatic.net/so/all.css?v=6184"> 

Where v=6184 is probably the SVN revision number.

Solution 4

ASP.NET MVC will handle this for you if you use bundles for your JS/CSS. It will automatically append a version number in the form of a GUID to your bundles and only update this GUID when the bundle is updated (aka any of the source files have changes).

This also helps if you have a ton of JS/CSS files as it can greatly improve content load times!

See Here

Solution 5

There are a built-in way in asp.net for this: bundling. Just use it. Each new version will have unique suffix "?v=XXXXXXX". In debug mode bundling is off, for switching on make setting in web.config:

<system.web>
    <compilation debug="false" />
</system.web>

Or add to the method RegisterBundles(BundleCollection bundles) :

BundleTable.EnableOptimizations = true;

For example:

BundleConfig.cs :

bundles.Add(new ScriptBundle("~/Scripts/myjavascript.js")
                .Include("~/Scripts/myjavascript.js"));

bundles.Add(new StyleBundle("~/Content/mystyle.css")
                .Include("~/Content/mystyle.css"));

_Layout.cshtml :

@Scripts.Render("~/Scripts/myjavascript.js")
@Styles.Render("~/Content/mystyle.css")
Share:
118,779

Related videos on Youtube

kiev
Author by

kiev

Updated on July 08, 2022

Comments

  • kiev
    kiev almost 2 years

    Some browsers cache js and css files, failing to refresh them unless you force them to. What's the easiest way.

    I just implemented this solution that seems to work.

    Declare a version variable on your page

      public string version { get; set; }
    

    Get the version number from web.config key

     version = ConfigurationManager.AppSettings["versionNumber"];
    

    In your aspx page make the calls to javascript and stylesheets like so

    <script src="scripts/myjavascript.js?v=<%=version %>" type="text/javascript"></script>
    <link href="styles/mystyle.css?v=<%=version %>" rel="stylesheet" type="text/css" />
    

    So if you set the version = 1.1 from 1.0 in your web.config your browser will download the latest files which will hopefully save you and your users some frustration.

    Is there another solution that works better, or will this cause any unforeseen issues for a website?

    • Brett Allen
      Brett Allen over 14 years
      Interesting question, I had the same issue recently, but was only an issue during development testing. Didn't care to much about it as we do not intend to change those file after launch. Would love to know a solution though for future reference!
    • monty
      monty over 10 years
      The only issue I can see is that changes to the web.config will, in the background, call an application restart: msdn.microsoft.com/en-us/library/aa478432.aspx
    • BetterLateThanNever
      BetterLateThanNever almost 7 years
      Thank you for the question. This helped me in solving a big issue.
  • Darren Kopp
    Darren Kopp over 14 years
    and uses copious amounts of bandwidth too.
  • kingdango
    kingdango over 10 years
    Right, you don't want a new version of the JS at each page load... you just want the browser to look for a new version each time you actually have an updated version.
  • kiev
    kiev over 10 years
    yes, the issue is with bandwidth - like in the comments above stackoverflow.com/a/2185918/59508
  • kiev
    kiev over 10 years
    this is great for mvc, I wonder if the latest mvc 5 framework handle this issue? The approach that bundling uses with -{version} wildcard is also a way to solve this problem, however it requires the files to be renamed after each new build...
  • Colbs
    Colbs almost 10 years
    This is perfectly acceptable for a temp solution on a 50KB css file while in development. +1
  • Bryan
    Bryan about 9 years
    I'm using the basics of your MVC example in a webforms website, and it's working great, so thank you for sharing!
  • Bryan
    Bryan about 9 years
    Should there be any reason to be concerned about displaying the last modified date/time stamp for resource files? If a file being used had a date/time stamp a few years past, could be information that a company might not want to be public to their users?
  • Tarun
    Tarun almost 9 years
    It's the standard way, mostly applications follows. But that time stamp should change only when you deploy or built your application. Otherwise every time user refresh page or switch to other pages in your application. Browser will download your all stylesheets and javascript again, which is not good
  • Flavia Obreja
    Flavia Obreja over 8 years
    Hey! Your example is working, but you should either remove the caching references or fix the code to use the cache because it can be confusing why you are using it. To use the cache you should add the version of the file to the cache using context.Cache.Add method in the case context.Cache[filename] == null . If the context.Cache[filename] != null then you should return the cached value (context.Cache[filename])
  • Bryan
    Bryan over 8 years
    Flavia, I think your explanation makes sense, and I think it's a simpler, more efficient implementation. Thanks for posting the helpful comments and feedback.
  • Jack
    Jack about 8 years
    Do you mean that if we use bundles in an MVC application, there is no need any of the methods in posted answer here? If so, bundling is really much more important I have ever thought. Could you please clarify us about these issue? Thanks.
  • metalheart
    metalheart almost 8 years
    this behavior is actually supported out of the box, see my answer
  • jonesy827
    jonesy827 almost 8 years
    Yes, exactly. As long as your scripts are included in a bundle, it will generate a version number automatically for each bundle when changes are detected in any of the bundle's source files.
  • Victor Zakharov
    Victor Zakharov over 7 years
    This would be a much more taxing approach than the one described in the accepted answer. Checking SVN version of the file every time a page is served is a performance overhead, especially as number of users increases over time.
  • Salik
    Salik over 7 years
    I have tried this method, but it adds the create date of the file, that's why it doesn't change version number on file overwrite.
  • dotnet-provoke
    dotnet-provoke over 7 years
    Great solution. Im using it but i had to modify the code for the cache to work:
  • Ramazan Binarbasi
    Ramazan Binarbasi about 7 years
    You can get revision number during build, write it into a file (e.g. partial .cs file), include that file in your project, so you don't need to read it from svn at runtime. I've used this approach with msbuild to put revision numbers in my AssemblyInfo.cs files from svn.
  • Federico Navarrete
    Federico Navarrete almost 7 years
    Man! You're awesome. Seriously, it's the best and unique! Thanks a lot!
  • Federico Navarrete
    Federico Navarrete almost 7 years
    Nice answer, but ASP MVC can a be a bit problematic if you don't consider what Adam explained because I tried it and the Bundle folder doesn't recognize it if you work with MVC 5. But thanks for the suggestion!
  • Federico Navarrete
    Federico Navarrete almost 7 years
    Nice approach too!
  • Federico Navarrete
    Federico Navarrete almost 7 years
    Thanks for letting us know! I didn't know it before!
  • VAAA
    VAAA over 6 years
    But this will only work in release or production environments. What about development when debug mode is on? Does bundle still fix this issue?
  • VAAA
    VAAA over 6 years
    Im trying to use bundle, with the optimization property equals true works great but I want to know if in a dev environment (debug on) the bundle still force browser to refresh scripts?
  • Adam Tegen
    Adam Tegen over 6 years
    Using a global version / revision number has at least one drawback: publishing a website update invalidates browser caches for all .js and .css files, not just the ones that changed. This probably does not matter in the majority of applications, but I mention it for completeness.
  • Durgesh Sonawane
    Durgesh Sonawane over 6 years
    What is the impact on the performance of the page? How much delay can it cause to load the page?
  • kristianp
    kristianp about 6 years
    If you update the version of your assemblyinfo.cs files automatically during a deployment or build, the minor version could be used for that number.
  • Tony Hinkle
    Tony Hinkle over 5 years
    By far the easiest way to do this, and probably the lowest overhead.
  • Brad Mathews
    Brad Mathews over 5 years
    Perfect solution. I also tested Chrome 70, Firefox 63 and IE 11 to make sure that caching was actually working. It is. This only busts caching on new versions of the file, at least on the latest versions of the browsers. I have heard mention elsewhere that some browsers reload every file with a querystring (?). Maybe that used be the case or maybe it is still true with Safari and Opera. DK.
  • SimplyInk
    SimplyInk over 5 years
    I like this, but am concerned why this solution has so little up votes...
  • JackArbiter
    JackArbiter over 5 years
    @SimplyInk I don't know, but there are 20 different answers, so that might have something do do with it. If it works and you like it, feel free to upvote it.
  • it3xl
    it3xl over 4 years
    Yeah, bundlind doesn't make developers live easier. You have to press Ctrl-F5 after each script change. And if you have frames it will be even more funny.
  • it3xl
    it3xl over 4 years
    And don't forget that you still have headaches as a developer. The ASP.NET bundling helps nohow during debugging and development.
  • Thanasis Ioannidis
    Thanasis Ioannidis almost 4 years
    this wil force download in every page render, even if the files has not changed at all.
  • SantoshK
    SantoshK almost 4 years
    @ThanasisIoannidis It can use where files are changes regularly. another option is add appVersion key in web.config and use with files name .. but you need to update when you release the application for prod.
  • sachin jaiswal
    sachin jaiswal about 3 years
    <caching enabled="true" enableKernelCache="true"> <profiles> <add extension=".html" policy="CacheUntilChange" kernelCachePolicy="CacheUntilChange"/> <add extension=".css" policy="CacheUntilChange" kernelCachePolicy="CacheUntilChange"/> <add extension=".js" policy="CacheUntilChange" kernelCachePolicy="CacheUntilChange"/> </profiles> </caching>
  • Mohammed Khurram
    Mohammed Khurram about 2 years
    This will get new version on every load and cause lot of data usage.