1

I would like to ask if there is a way to prevent Firefox from caching scripts (.js files).

I have a project (ASP.Net Web App) with caching issue on firefox. When I first run the application (script is being cached on firefox) and modify the script and rerun the application, firefox is using the cached script instead of the updated one.

I'm using Firefox 3.6.13.

I already tried using HttpHeaders but it seems like firefox is ignoring my codes.

Here is my code:

    HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    HttpContext.Current.Response.Cache.SetAllowResponseInBrowserHistory(false);
    HttpContext.Current.Response.Cache.SetExpires(DateTime.UtcNow.AddMinutes(-1));
    HttpContext.Current.Response.Cache.SetNoStore();

I tried placing this code at global.asax > Application_BeginRequest and at MasterPage.aspx.cs > Page_Load, but it isn't working.

Thanks in advance.

KaeL
  • 3,639
  • 2
  • 28
  • 56
  • Are you trying to prevent caching for development environment only? If yes, have you tried setting Firefox to not cache anything in Tools -> Options -> Privacy tab? – Puneet Feb 21 '11 at 07:41
  • a hacky workaround is to append a querystring to your script so that ff thinks it is new – mrtsherman Feb 21 '11 at 07:41
  • Hi, this issue was reported from Production of my project, so unfortunately, it isn't appropriate to tell the user to set their firefox not to cache anything. :( – KaeL Feb 21 '11 at 07:47
  • @Kael Ah, in that case, I'll remove my comment. – Sem Vanmeenen Feb 21 '11 at 07:56
  • @mrtsherman Thanks, I've already come with the querystring technique, I am just thinking if there is any more option to work this around. – KaeL Feb 21 '11 at 08:01
  • @KaeL By the way, why prevent javascript from being cached? – Magnus Feb 23 '11 at 13:03
  • @Magnus: Sorry for very late reply. My javascript is being updated most of the time. That's why I need to prevent it from being cached. THanks! – KaeL Mar 09 '11 at 10:35

6 Answers6

3

One technique is to add a random element to the URL as a querystring, so the browser doesn't know how to cache the script:

<script src="jquery.js?<%=DateTime.Now.Ticks %>" />

Even better would be to append the current build number of your assembly, so you get the performance benefits of script caching while the script hasn't changed. This only works however, if you never change your script files "out of band" with your binary releases.

jevakallio
  • 35,324
  • 3
  • 105
  • 112
  • Hi! Thanks for the answer. :D I've already tried this one (querystring) and it solves the caching issue, but i'm looking for a more programmatic way if there is any, like setting it from code behind. – KaeL Feb 21 '11 at 07:49
  • You can alwyas use RegisterClientScriptBlock from codebehind and than add the Ticks – Magnus Feb 21 '11 at 08:16
  • @Magnus: What I mean is if there are any other options rather than using querystring which I can set from code behind. ^_^ – KaeL Feb 21 '11 at 08:36
1

1) Install IIS module: http://www.iis.net/download/urlrewrite

2) Put this in web.config into section:

 <rewrite>
    <rules>
      <rule name="Style Rewrite" stopProcessing="true">
        <match url="^v(.*?)/styles/(.*)" />
        <action type="Rewrite" url="/styles/{R:2}" />
      </rule>
      <rule name="Javascript Rewrite" stopProcessing="true">
        <match url="^v(.*?)/javascript/(.*)" />
        <action type="Rewrite" url="/javascript/{R:2}" />
      </rule>
    </rules>
  </rewrite>

3) Write this helper function (into some global class)

public static string PutCSS(string filepath)
{
    FileInfo f = new FileInfo(HttpContext.Current.Server.MapPath(filepath));
    string timestamp = f.LastWriteTimeUtc.Year.ToString() + f.LastWriteTimeUtc.Month.ToString() + f.LastWriteTimeUtc.Day.ToString() + f.LastWriteTimeUtc.Hour.ToString() + f.LastWriteTimeUtc.Minute.ToString() + f.LastWriteTimeUtc.Second.ToString() + f.LastWriteTimeUtc.Millisecond.ToString();
    return "<link type=\"text/css\" rel=\"stylesheet\" href=\"v" + timestamp + "/" + filepath + "\" />\n";
}

public static string PutJS(string filepath)
{
    FileInfo f = new FileInfo(HttpContext.Current.Server.MapPath(filepath));
    string timestamp = f.LastWriteTimeUtc.Year.ToString() + f.LastWriteTimeUtc.Month.ToString() + f.LastWriteTimeUtc.Day.ToString() + f.LastWriteTimeUtc.Hour.ToString() + f.LastWriteTimeUtc.Minute.ToString() + f.LastWriteTimeUtc.Second.ToString() + f.LastWriteTimeUtc.Millisecond.ToString();
    return "<script type=\"text/javascript\" src=\"v" + timestamp + "/" + filepath + "\" ></script>\n";
}

4) Instead of:

<link href="Styles/style.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="Javascript/userscript.js" ></script>

Use:

<%= global.PutCSS("Styles/style.css")%>
<%= global.PutCSS("Javascript/userscript.css")%>
MartinCermak
  • 111
  • 1
  • 4
1

You should be able to use

HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);

but you will have to have a http handler that renders the script directly to the response stream and than set the source url of the script tag to the handler or configure IIS to handle all javascripts using a specific handler: Point *.js to the aspnet_isapi.dll ISAPI Extension and than add the following in your web.config

<system.web>
    <httpHandlers>
        <!-- javascript handler -->
        <add verb="*" path="*.js" 
         type="skmHttpHandlers.JavascriptHandler, skmHttpHandlers" />
    </httpHandlers>

And than the handler:

namespace skmHttpHandlers
{
   public class JavascriptHandler : IHttpHandler
   {
      public void ProcessRequest(HttpContext context)
      {
         context.Response.Clear();
         context.Response.Cache.SetCacheability(HttpCacheability.NoCache)
         using (var scriptStream = File.Open(Server.MapPath("~/script/TheScript.js"), FileMode.Open))
           scriptStream.CopyTo(context.Response.OutputStream);
         context.Response.End();
      }

      public bool IsReusable
      {
         get
         {
            return false;
         }
      }
   }
}
Magnus
  • 45,362
  • 8
  • 80
  • 118
  • Hi! Thanks for the answer. I'm new to HttpHandlers. I'm searching on how to render script using that, but no luck. Can you show me a sample code? – KaeL Feb 22 '11 at 02:33
  • Thanks Magnus for the codes. I'll be looking into this and post my updates after testing this. :) – KaeL Feb 22 '11 at 10:28
  • Hi I tested this one but firefox still doesn't update the script. Here is my code (I'm not 100% sure if I'm doing the right thing, but I was able to render the script using HttpHandler). – KaeL Feb 23 '11 at 08:04
  • @Web.config: ` ` – KaeL Feb 23 '11 at 08:04
  • @ScriptHandler: `context.Response.Cache.SetCacheability(HttpCacheability.NoCache); context.Response.Cache.SetAllowResponseInBrowserHistory(false); context.Response.Cache.SetExpires(DateTime.UtcNow.AddMinutes(-1)); context.Response.Cache.SetNoStore(); string script = ""; script = script.Replace("//", "/"); context.Response.Write(script);` – KaeL Feb 23 '11 at 08:06
  • Then @MasterPage.aspx.cs > Page_Load: `protected void Page_Load(object sender, EventArgs e) { ScriptHandler sh = new ScriptHandler(); sh.ProcessRequest(new HttpContext(HttpContext.Current.Request, HttpContext.Current.Response)); }` – KaeL Feb 23 '11 at 08:06
  • @KaeL You should render the script not the link to the script, see my edit. An then just register the script tag as usual on the page. The handler will load instead of the script file, and then the handler renders the script without cache. – Magnus Feb 23 '11 at 08:38
  • Hi, how should I set the source url of the script tag to the handler? I'm trying this one: `` but is not referring to the script. Sorry for my questions (I feel like I'm very stupid XD) – KaeL Feb 23 '11 at 10:48
  • If handler is set up correctly in IIS and Webconfig you would only need to write – Magnus Feb 23 '11 at 12:58
  • Hi, correct me if I'm wrong, so after setting up my webconfig, creating the Handler and adding the normal ` – KaeL Feb 24 '11 at 01:55
  • Hi I was able to test this code and its working! Thanks, I learned a lot from you with regards to HttpHandlers. :D – KaeL Feb 24 '11 at 05:34
0
<head runat="server">
    <%= "<link href='/asset/Style.css?v" + new Random().Next(1000,9999).ToString() + "' rel='stylesheet' />" %>
</head>
0

If you have control over the IIS configuration then you can put all your scripts inside one folder and tell IIS to expire the content immediately, or add other custom headers of your choice.

The appropriate page for IIS 6.0 is http://technet.microsoft.com/en-us/library/cc732442.aspx

Neil
  • 54,642
  • 8
  • 60
  • 72
  • Hi I've already come up with HttpHeader configuration at IIS, but we have issues in controlling IIS in our Production Site. But definitely this will work. Thanks! :D – KaeL Feb 24 '11 at 01:19
0

I WANT the scripts and the styles to be cached... only reload them when they change... It is easy using the date of the file:

<script type="text/javascript" src="~/js/custom.js?d=@(System.Text.RegularExpressions.Regex.Replace(File.GetLastWriteTime(Server.MapPath("~/js/custom.js")).ToString(),"[^0-9]", ""))"></script>


<link rel="stylesheet" href="~/css/custom.css?d=@(System.Text.RegularExpressions.Regex.Replace(File.GetLastWriteTime(Server.MapPath("~/css/custom.css")).ToString(),"[^0-9]", ""))" />