112

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?

Safeer Hussain
  • 1,230
  • 1
  • 15
  • 27
kiev
  • 2,040
  • 9
  • 32
  • 54
  • 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! – Brett Allen Feb 02 '10 at 16:53
  • The only issue I can see is that changes to the web.config will, in the background, call an application restart: http://msdn.microsoft.com/en-us/library/aa478432.aspx – monty Dec 09 '13 at 23:18
  • Thank you for the question. This helped me in solving a big issue. – BetterLateThanNever May 31 '17 at 18:57

23 Answers23

83

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>
Daniel Leach
  • 5,517
  • 4
  • 18
  • 32
Adam Tegen
  • 25,378
  • 33
  • 125
  • 153
  • 1
    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... – kiev Jan 24 '14 at 15:16
  • I'm using the basics of your MVC example in a webforms website, and it's working great, so thank you for sharing! – Bryan Apr 30 '15 at 15:28
  • 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? – Bryan Apr 30 '15 at 16:44
  • 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 – Tarun Jun 05 '15 at 06:28
  • 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. – Salik Nov 08 '16 at 09:03
  • Great solution. Im using it but i had to modify the code for the cache to work: – dotnet-provoke Nov 13 '16 at 09:06
  • Man! You're awesome. Seriously, it's the best and unique! Thanks a lot! – Federico Navarrete Jul 14 '17 at 08:54
  • 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? – VAAA Aug 12 '17 at 11:55
  • 3
    What is the impact on the performance of the page? How much delay can it cause to load the page? – Durgesh Sonawane Nov 13 '17 at 06:10
46

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" />
meze
  • 14,975
  • 4
  • 47
  • 52
metalheart
  • 3,740
  • 1
  • 23
  • 29
29

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.

Daniel Vassallo
  • 337,827
  • 72
  • 505
  • 443
  • 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. – Victor Zakharov Aug 19 '16 at 21:03
  • 5
    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. – Ramazan Binarbasi May 09 '17 at 21:14
  • 2
    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. – Adam Tegen Aug 15 '17 at 01:27
  • 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. – kristianp Mar 23 '18 at 01:14
18

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

jonesy827
  • 302
  • 3
  • 11
  • 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. – Jack Mar 25 '16 at 22:12
  • 1
    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. – jonesy827 Jul 11 '16 at 21:24
  • And don't forget that you still have headaches as a developer. The ASP.NET bundling helps nohow during debugging and development. – it3xl Sep 28 '19 at 06:17
12

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")
Alex Tkachuk
  • 1
  • 1
  • 3
  • 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 Aug 12 '17 at 11:53
  • 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 Sep 28 '19 at 06:09
9

I wanted a simple one liner to make the path unique to bust the cache. This worked for me:

<script src="scripts/main.js?bust_js_cache=<%=System.IO.File.GetLastWriteTime(Server.MapPath("scripts/main.js")).ToString("HH:mm:ss")%>" type="text/javascript"></script>

If the file has been modified since the last time it was loaded on the page the browser will pull the updated file.

It generates the last modified stamp from the .js file and chucks it in there instead of the version which may not be easy to gain access to.

<script src="scripts/main.js?bust_js_cache=10:18:38" type="text/javascript"></script>

Another option could be to get the checksum of the file.

sniperd
  • 5,124
  • 6
  • 28
  • 44
  • 1
    By far the easiest way to do this, and probably the lowest overhead. – Tony Hinkle Sep 18 '18 at 20:17
  • 1
    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. – Brad Mathews Oct 29 '18 at 17:47
7

There is a simpler answer to this than the answer given by the op in the question (the approach is the same):

Define the key in the web.config:

<add key="VersionNumber" value="06032014"/>

Make the call to appsettings directly from the aspx page:

<link href="styles/navigation.css?v=<%=ConfigurationManager.AppSettings["VersionNumber"]%>" rel="stylesheet" type="text/css" />
JackArbiter
  • 5,705
  • 2
  • 27
  • 34
  • I like this, but am concerned why this solution has so little up votes... – SimplyInk Jan 23 '19 at 04:20
  • @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. – JackArbiter Jan 23 '19 at 04:58
5

Based on Adam Tegan's answer, modified for use in a web forms application.

In the .cs class code:

public static class FileUtility
{
    public static string SetJsVersion(HttpContext context, string filename) {
        string version = GetJsFileVersion(context, filename);
        return filename + version;
    }

    private static string GetJsFileVersion(HttpContext context, string filename)
    {
        if (context.Cache[filename] == null)
        {
            string filePhysicalPath = context.Server.MapPath(filename);

            string version = "?v=" + GetFileLastModifiedDateTime(context, filePhysicalPath, "yyyyMMddhhmmss");

            return version;
        }
        else
        {
            return string.Empty;
        }
    }

    public static string GetFileLastModifiedDateTime(HttpContext context, string filePath, string dateFormat)
    {
        return new System.IO.FileInfo(filePath).LastWriteTime.ToString(dateFormat);
    }
}

In the aspx markup:

<script type="text/javascript" src='<%= FileUtility.SetJsVersion(Context,"/js/exampleJavaScriptFile.js") %>'></script>

And in the rendered HTML, it appears as

<script type="text/javascript" src='/js/exampleJavaScriptFile.js?v=20150402021544'></script>
Community
  • 1
  • 1
Bryan
  • 3,629
  • 2
  • 28
  • 27
  • 2
    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]) – Flavia Obreja Oct 12 '15 at 07:32
  • 1
    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. – Bryan Oct 12 '15 at 12:26
4

Interestingly, this very site has issues with the approach you describe in connection with some proxy setups, even though it should be fail-safe.

Check this Meta Stack Overflow discussion.

So in light of that, it might make sense not to use a GET parameter to update, but the actual file name:

href="/css/scriptname/versionNumber.css" 

even though this is more work to do, as you'll have to actually create the file, or build a URL rewrite for it.

Community
  • 1
  • 1
Pekka
  • 442,112
  • 142
  • 972
  • 1,088
4

Here's an approach that works with ASP.NET 5 / MVC 6 / vNext.

Step 1: Create a class to return the last write time of the file, similar to other answers in this thread. Note, this requires ASP.NET 5 (or other) dependency injection.

public class FileVersionService
{
    private IHostingEnvironment _hostingEnvironment;
    public FileVersionService(IHostingEnvironment hostingEnvironment)
    {
        _hostingEnvironment = hostingEnvironment;
    }

    public string GetFileVersion(string filename)
    {
       var path = string.Format("{0}{1}", _hostingEnvironment.WebRootPath, filename);
       var fileInfo = new FileInfo(path);
       var version = fileInfo.LastWriteTimeUtc.ToString("yyyyMMddhhmmssfff");
       return version;
     }
}

Step 2: Register the service to be injected inside startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddScoped<FileVersionService>();
    ...
}

Step 3: Then, in ASP.NET 5, it is possible to inject the service directly into a layout view such as _Layout.cshtml like this:

@inject Namespace.Here.FileVersionService fileVersionService
<!DOCTYPE html>
<html lang="en" class="@ViewBag.HtmlClass">
<head>
    ...
    <link href="/css/styles.css?v=@fileVersionService.GetFileVersion("\\css\\styles.css")" rel="stylesheet" />
    ...
</head>
<body>
    ...
</body>

There are some finishing touches that could be done to combine physical paths better and handle the file name in a style more consistent with the syntax, but this is a starting point. Hope it helps people moving to ASP.NET 5.

Ender2050
  • 6,912
  • 12
  • 51
  • 55
  • this behavior is actually supported out of the box, see [my answer](http://stackoverflow.com/questions/2185872/force-browsers-to-get-latest-js-and-css-files-in-asp-net-application/37433387#37433387) – metalheart May 25 '16 at 09:47
3

I have employed a slightly different technique in my aspnet MVC 4 site:

_ViewStart.cshtml:

@using System.Web.Caching
@using System.Web.Hosting
@{
    Layout = "~/Views/Shared/_Layout.cshtml";
    PageData.Add("scriptFormat", string.Format("<script src=\"{{0}}?_={0}\"></script>", GetDeployTicks()));
}

@functions
{

    private static string GetDeployTicks()
    {
        const string cacheKey = "DeployTicks";
        var returnValue = HttpRuntime.Cache[cacheKey] as string;
        if (null == returnValue)
        {
            var absolute = HostingEnvironment.MapPath("~/Web.config");
            returnValue = File.GetLastWriteTime(absolute).Ticks.ToString();
            HttpRuntime.Cache.Insert(cacheKey, returnValue, new CacheDependency(absolute));
        }
        return returnValue;
    }
}

Then in the actual views:

 @Scripts.RenderFormat(PageData["scriptFormat"], "~/Scripts/Search/javascriptFile.min.js")
2

Starting from the above answer I modified a little bit the code to make the helper work with CSS files too and add a version every time when you do some change in the files and not only when you do the build

public static class HtmlHelperExtensions
{
    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>");
    }

    public static MvcHtmlString IncludeVersionedCss(this HtmlHelper helper, string filename)
    {
        string version = GetVersion(helper, filename);
        return MvcHtmlString.Create("<link href='" + filename + version + "' type ='text/css' rel='stylesheet'/>");
    }

    private static string GetVersion(this HtmlHelper helper, string filename)
    {
        var context = helper.ViewContext.RequestContext.HttpContext;
        var physicalPath = context.Server.MapPath(filename);
        var version = "?v=" +
        new System.IO.FileInfo(physicalPath).LastWriteTime
        .ToString("yyyyMMddHHmmss");
        context.Cache.Add(physicalPath, version, null,
          DateTime.Now.AddMinutes(1), TimeSpan.Zero,
          CacheItemPriority.Normal, null);

        if (context.Cache[filename] == null)
        {
            context.Cache[filename] = version;
            return version;
        }
        else
        {
            if (version != context.Cache[filename].ToString())
            {
                context.Cache[filename] = version;
                return version;
            }
            return context.Cache[filename] as string;
        }
    }
}
Community
  • 1
  • 1
Sergi Mulà
  • 104
  • 3
2

<?php $rand_no = rand(10000000, 99999999)?> <script src="scripts/myjavascript.js?v=<?=$rand_no"></script>

This works for me in all browsers. Here I have used PHP to generate random no. You can use your own server side language.`

Mukesh Rai
  • 11
  • 3
  • 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 Jul 14 '17 at 08:55
1

Get file modified time, as shown below

private static string GetLastWriteTimeForFile(string pathVal)
    {
        return System.IO.File.GetLastWriteTime(HostingEnvironment.MapPath(pathVal)).ToFileTime().ToString();
    }

Append this with input as querystring

public static string AppendDateInFile(string pathVal)
    {
        var patheWithDate = new StringBuilder(pathVal);
        patheWithDate.AppendFormat("{0}x={1}",
                               pathVal.IndexOf('?') >= 0 ? '&' : '?',
                               GetLastWriteTimeForFile(pathVal));
        return patheWithDate.ToString();
    }

Call this from markup.

MVC Extension Helper Approach

Add an extension method

namespace TNS.Portal.Helpers
{
    public static class ScriptExtensions
    {
        public static HtmlString QueryStringScript<T>(this HtmlHelper<T> html, string path)
        {
            var file = html.ViewContext.HttpContext.Server.MapPath(path);
            DateTime lastModified = File.GetLastWriteTime(file);
            TagBuilder builder = new TagBuilder("script");
            builder.Attributes["src"] = path + "?modified=" + lastModified.ToString("yyyyMMddhhmmss");
            return new HtmlString(builder.ToString());
        }

       public static HtmlString QueryStringStylesheet<T>(this HtmlHelper<T> html, string path)
       {
        var file = html.ViewContext.HttpContext.Server.MapPath(path);
        DateTime lastModified = File.GetLastWriteTime(file);
        TagBuilder builder = new TagBuilder("link");
        builder.Attributes["href"] = path + "?modified=" + lastModified.ToString("yyyyMMddhhmmss");
        builder.Attributes["rel"] = "stylesheet";
        return new HtmlString(builder.ToString());
      }

    }
}

Add this namespace in web.config

<system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <pages pageBaseType="System.Web.Mvc.WebViewPage">
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Optimization"/>
        <add namespace="System.Web.Routing" />
        <add namespace="TNS.Portal" />
        <add namespace="TNS.Portal.Helpers" />
      </namespaces>
    </pages>
  </system.web.webPages.razor>

Use it in view as

@Html.QueryStringScript("/Scripts/NPIAjaxCalls.js")
@Html.QueryStringStylesheet("/Content/StyledRadio.css")
LCJ
  • 22,196
  • 67
  • 260
  • 418
1

Simplified prior suggestions and providing code for .NET Web Forms developers.

This will accept both relative ("~/") and absolute urls in the file path to the resource.

Put in a static extensions class file, the following:

public static string VersionedContent(this HttpContext httpContext, string virtualFilePath)
{
    var physicalFilePath = httpContext.Server.MapPath(virtualFilePath);
    if (httpContext.Cache[physicalFilePath] == null)
    {
        httpContext.Cache[physicalFilePath] = ((Page)httpContext.CurrentHandler).ResolveUrl(virtualFilePath) + (virtualFilePath.Contains("?") ? "&" : "?") + "v=" + File.GetLastWriteTime(physicalFilePath).ToString("yyyyMMddHHmmss");
    }
    return (string)httpContext.Cache[physicalFilePath];
}

And then call it in your Master Page as such:

<link type="text/css" rel="stylesheet" href="<%= Context.VersionedContent("~/styles/mystyle.css") %>" />
<script type="text/javascript" src="<%= Context.VersionedContent("~/scripts/myjavascript.js") %>"></script>
0

The main problem with doing it this way is mainly that you will need to remember to update your version number in your code every time you make any change to your css or js files.

A possibly better way to do it is to set a guaranteed unique parameter with each of your css or js files, like so:

<script src="scripts/myjavascript.js?_=<%=DateTime.Now.Ticks%>" type="text/javascript"></script>
<link href="styles/mystyle.css?_=<%=DateTime.Now.Ticks%>" rel="stylesheet" type="text/css" />

This forces the files to be requested from the server every single time, which also means that your site will not be as performant upon page load, since those files will never be cached, and will use unneeded bandwidth each time.

Essentially, if you can remember to update the version number every time a change is made, you can get away with how you're doing it.

Tim S. Van Haren
  • 8,861
  • 2
  • 30
  • 34
0

Based on the above answer I've written a small extension class to work with CSS and JS files:

public static class TimestampedContentExtensions
{
    public static string VersionedContent(this UrlHelper helper, string contentPath)
    {
        var context = helper.RequestContext.HttpContext;

        if (context.Cache[contentPath] == null)
        {
            var physicalPath = context.Server.MapPath(contentPath);
            var version = @"v=" + new FileInfo(physicalPath).LastWriteTime.ToString(@"yyyyMMddHHmmss");

            var translatedContentPath = helper.Content(contentPath);

            var versionedContentPath =
                contentPath.Contains(@"?")
                    ? translatedContentPath + @"&" + version
                    : translatedContentPath + @"?" + version;

            context.Cache.Add(physicalPath, version, null, DateTime.Now.AddMinutes(1), TimeSpan.Zero,
                CacheItemPriority.Normal, null);

            context.Cache[contentPath] = versionedContentPath;
            return versionedContentPath;
        }
        else
        {
            return context.Cache[contentPath] as string;
        }
    }
}

Instead of writing something like:

<link href="@Url.Content(@"~/Content/bootstrap.min.css")" rel="stylesheet" type="text/css" />
<script src="@Url.Content(@"~/Scripts/bootstrap.min.js")"></script>

You can now write:

<link href="@Url.VersionedContent(@"~/Content/bootstrap.min.css")" rel="stylesheet" type="text/css" />
<script src="@Url.VersionedContent(@"~/Scripts/bootstrap.min.js")"></script>

I.e. simply replace Url.Content with Url.VersionedContent.

Generated URLs look something like:

<link href="/Content/bootstrap.min.css?v=20151104105858" rel="stylesheet" type="text/css" />
<script src="/Scripts/bootstrap.min.js?v=20151029213517"></script>

If you use the extension class you might want to add error handling in case the MapPath call doesn't work, since contentPath isn't a physical file.

Community
  • 1
  • 1
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
0

I use a similar way to do the same you are doing without modifying each page. Added a PreRender event is master file. It keeps my logic at one place and applicable to both js and css files.

protected void Page_PreRender(object sender, EventArgs e)
    {
        HtmlLink link = null;
        LiteralControl script = null;


        foreach (Control c in Header.Controls)
        {
            //StyleSheet add version
            if (c is HtmlLink)
            {
                link = c as HtmlLink;


                if (link.Href.EndsWith(".css", StringComparison.InvariantCultureIgnoreCase))
                {
                    link.Href += string.Format("?v={0}", ConfigurationManager.AppSettings["agVersion"]);
                }

            }

            //Js add version
            if (c is LiteralControl)
            {
                script = c as LiteralControl;

                if (script.Text.Contains(".js"))
                {
                    var foundIndexes = new List<int>();


                    for (int i = script.Text.IndexOf(".js\""); i > -1; i = script.Text.IndexOf(".js\"", i + 1))
                    {

                        foundIndexes.Add(i);
                    }

                    for (int i = foundIndexes.Count - 1; i >= 0; i--)
                    {

                        script.Text = script.Text.Insert(foundIndexes[i] + 3, string.Format("?v={0}", ConfigurationManager.AppSettings["agVersion"]));
                    }
                }

            }

        }
    }
Jay
  • 133
  • 2
  • 12
0

You can override the DefaultTagFormat property of Scripts or Styles.

Scripts.DefaultTagFormat = @"<script src=""{0}?v=" + ConfigurationManager.AppSettings["pubversion"] + @"""></script>";
Styles.DefaultTagFormat = @"<link href=""{0}?v=" + ConfigurationManager.AppSettings["pubversion"] + @""" rel=""stylesheet""/>";
phoenix
  • 475
  • 1
  • 5
  • 14
0

For resolving this issue in my ASP.Net Ajax application, I created an extension and then called in the master page.

For more details, you can go through the link.

Kasim Husaini
  • 392
  • 3
  • 14
0

Easy and smart way to implement css versioning in .net application by below concept.. no need to write back-end code.

<link href="<%="../../App_Themes/Base/css/main.css?v="+ DateTime.Now.ToString("yyyyMMddhhmmss") +""%>" rel="stylesheet" />
SantoshK
  • 1,789
  • 16
  • 24
  • this wil force download in every page render, even if the files has not changed at all. – Thanasis Ioannidis Jun 26 '20 at 09:21
  • @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. – SantoshK Jun 29 '20 at 09:13
-3

For ASP.NET pages I am using the following

BEFORE

<script src="/Scripts/pages/common.js" type="text/javascript"></script>

AFTER (force reload)

 <script src="/Scripts/pages/common.js?ver<%=DateTime.Now.Ticks.ToString()%>" type="text/javascript"></script>

Adding the DateTime.Now.Ticks works very well.

Ravi Ram
  • 24,078
  • 21
  • 82
  • 113
  • yes, the issue is with bandwidth - like in the comments above http://stackoverflow.com/a/2185918/59508 – kiev Jan 24 '14 at 15:05
-4

just put this inside system.webserver in web.config

<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>
il_raffa
  • 5,090
  • 129
  • 31
  • 36