Disable browser cache for entire ASP.NET website
Asked Answered
A

8

204

I am looking for a method to disable the browser cache for an entire ASP.NET MVC Website

I found the following method:

Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);
Response.Cache.SetNoStore();

And also a meta tag method (it won't work for me, since some MVC actions send partial HTML/JSON through Ajax, without a head, meta tag).

<meta http-equiv="PRAGMA" content="NO-CACHE">

But I am looking for a simple method to disable the browser cache for an entire website.

Alphabetize answered 21/7, 2009 at 15:52 Comment(1)
possible duplicate of How can I disable client side and proxy caching in ASP.NET MVC?Intromit
S
94
HttpContext.Current.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
HttpContext.Current.Response.Cache.SetValidUntilExpires(false);
HttpContext.Current.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
HttpContext.Current.Response.Cache.SetNoStore();

All requests get routed through default.aspx first - so assuming you can just pop in code behind there.

Supinate answered 21/7, 2009 at 16:0 Comment(8)
I would put it into Global.asax.cs in Application_BeginRequest(). I don't trust this default.aspx thing... Another question: does this have precedence over [OutputCache] attributes?Ilysa
I like the idea of simply creating a Global Action Filter an putting this stuff in that way. Negates the need to worry about Default.aspx and Global.asax.Gaudery
Putting this in Application_BeingRequest can cause some issues. If your images get routed through the .net runtime (which can happen if you're using wildcard mapping for nice urls) then no images will be cached on the browser. This can REALLY slow down your page load times as each page request will re-download all images.Traveller
Using anything programmatically will always override any declared Attribute. In other words, using the OP's code will override any declared [OutputCache] attribute.Utley
Any thoughts on how to smoke test and verify that the cache disable is actually working?Cody
Easiest smoke test would be to Logout and press your back button to see if the previous page (requiring authorization) renders or redirects you to login. A better test would be to use something like FireBug to review caching (you will see lots of 200 OK instead of 304 not modified in the Net panel)Electrokinetics
@herbrandson, where do you suggest this code is placed if not in the Application_BeginRequest()?Enamor
@MatthewT.Baker Unfortunately it's been a little while since I left this response (and since I worked on a .net web app) and I don't recall off hand where we had placed this logic. It seems like there are multiple options. It also partly depends on if you're using web forms or mvc. If you're using mvc, checkout out the answer from JKG for an example using an IActionFilter.Traveller
S
369

Create a class that inherits from IActionFilter.

public class NoCacheAttribute : ActionFilterAttribute
{  
    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        filterContext.HttpContext.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
        filterContext.HttpContext.Response.Cache.SetValidUntilExpires(false);
        filterContext.HttpContext.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
        filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
        filterContext.HttpContext.Response.Cache.SetNoStore();

        base.OnResultExecuting(filterContext);
    }
}

Then put attributes where needed...

[NoCache]
[HandleError]
public class AccountController : Controller
{
    [NoCache]
    [Authorize]
    public ActionResult ChangePassword()
    {
        return View();
    }
}
Schoolbook answered 10/11, 2009 at 1:28 Comment(18)
Rather than HttpContext.Current.Response, you should probably use filterContext.HttpContext.Response since HttpContext.Current returns the pre-MVC HttpContext object and the filterContext.HttpContext returns the post-MVC HttpContextBase. It increases testability and consistency.Mornings
Good catch and lazy on my part, I've made the changes.Schoolbook
IActionFilter is already implemented on the ActionFilterAttribute, so you don't need to repeat it.Keslie
In current versions of ASP.NET MVC you can simply use OutputCacheAttribute to prevent caching: [OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")]Fung
Isn't the OutputCacheAttribute only for the server caching? But Palani's question is about browser caching..Dangelo
@jhexp, OutputCache and setting Response.Cache is (almost) the same thing, except some minor limitations on OutputCache.Hexone
@bill-yang Thats true, good point. But there is still a difference between browser caching (controlled by the meta tags or SetExpires() etc) and the ASP.NET Output caching (OutputcacheAttribute and Response.Cache()). For example you may want to completely disable browser caching, but use output caching (to achieve "donut" caching). Its bit offtopic now, but the original question was only about browser cache, eg setting the right metatags and http response headers.Dangelo
I'd like to point out that I just spent several days using every "put this in your code to stop caching" solution under the sun for ASP.NET MVC, including the accepted answer to this question, to no avail. This answer - the attribute - worked. +1M Rep if I could...Quijano
You might want to add if (filterContext.IsChildAction) return; at the top - this will prevent the outer action to be 'no cached' if it calls a child action that is decorated with NoCache attribute. In other words NoCache attribute won't leak to other actions if they execute child actions. Also, the class name should be NoCacheAttribute to comply with generally accepted naming convention for attributes.Rapine
The caching in my case was due to an html. We changed on homepage some a href links from blabla.aspx to #, but after a post and press back back button in IE9, the presented html was the old one with blabla.aspx :-/ Output cache did not solve our problem, and we don't want to mess with cacheability. So we changed the port of the web application in VS2010 and now it seems to be fixed.Stacy
Another benefit of this method is that it does not cause issues with RenderAction as the [OutputCache] attribute can see #4798468Menado
+1 Nice answer! But what about using OnResultExecuted instead of OnResultExecuting? Things can be changed when the ActionResult has a override ExecuteResult method. OnResultExecuted did the operation at last which guarantees the result won't be cached. Is it better?Munn
How would you override this to enable caching in some Actions of the Controller while the NoCache attribute was put on the Controller? Can't get that to work.Straightway
This solution didn't work for me either. I'm losing the will to live.Wendish
+1 for the example. Makes it easier to understand when using it for the first time.Gentilesse
This answer didn't seem to work when testing with chrome and the default IISExpress. I checked chrome dev tools if the headers were being set and they were. I also tried adding "SetAllowResponseInBrowserHistory(false)", however chrome just doesn't care and the back button works fine; no "page expired" message.Pyrrolidine
@AshleyTate that didn't seem to work for me, "duration must be a positive number" when applying it to the controllerPotto
I have two comments for the first code block: Firstly, the SetExpires() call is actually not necessary, since the SetCacheability() also sets the expiration to "-1". Secondly, I don't think the SetValidUntilExpires() call is necessary, since logically it only changes the behavior of the ASP.NET pipeline to not care about cache headers from the client, but if I understand correctly we disable all caching anyway so this is probably not necessary.Affer
C
132

Instead of rolling your own, simply use what's provided for you.

As mentioned previously, do not disable caching for everything. For instance, jQuery scripts used heavily in ASP.NET MVC should be cached. Actually ideally you should be using a CDN for those anyway, but my point is some content should be cached.

What I find works best here rather than sprinkling the [OutputCache] everywhere is to use a class:

[System.Web.Mvc.OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public class NoCacheController  : Controller
{
}

All of your controllers you want to disable caching for then inherit from this controller.

If you need to override the defaults in the NoCacheController class, simply specify the cache settings on your action method and the settings on your Action method will take precedence.

[HttpGet]
[OutputCache(NoStore = true, Duration = 60, VaryByParam = "*")]
public ViewResult Index()
{
  ...
}
Concealment answered 5/4, 2011 at 1:57 Comment(12)
In my experience changing the OutputCache duration merely changes the duration that the page is stored in IIS's OutputCache - i.e. the dynamic content cache on the web server - it has nothing to do with browser caching settings. The answer above with an ActionFilter solves the problem of disabling browser caching.Bruise
@Ozziepeeps, your comment is not correct. The msdn docs discuss browser caching as well as a simple test will show this attribute changes the cache-control response header to "Cache-Control: public, no-store, max-age=0" from "Cache-Control: private" without using the attribute.Concealment
also fyi - you can control all three locations (server, proxy, client) with this attribute so absolutely can control beyond the server cache. See asp.net/mvc/tutorials/… for some additional details.Concealment
Ok, thanks @Adam Tuliper. I guess I must have been seeing some spurious behaviour. In my project, we actually needed to disable Output Caching on IIS for other reasons, so resorted to implementing a no-cache action filter similar to the aboveBruise
+1 "If you need to override the defaults in the NoCacheController class simply specify the cache settings on your action method and the settings on your Action method will take precedence."Nephogram
Please note that if you use [System.Web.Mvc.OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")] at the class level, you can't have PartialViews in your class.Terrier
@Daniel Allen Langdon You are right this method really messes up peopel that use partials I'm going to try the NOCache attribute insteadClaudianus
The OutputCache method didn't prevent IE caching when two conditions were present: 1) the action took no parameters and 2) the action returned only text via Content(someText). When I return JSON and take a parameter, IE caching is properly defeated.Tem
Interesting @KaseySpeakman , I'll have to test that out a bit more to see why IE does this and if the headers come down or not, but are ignored because its text, etc. ThanksConcealment
@DanielAllenLangdon and Chris Stephens - Why wouldn't this work for partial views?Nucleolated
If I recall one of the params prevents partials from using these settings at a class level. Not sure if this resolved in mvc4 or not thoughConcealment
@Kasey Speakman Thanks for verifying what I have been seeing. This solution does not disable all caching scenarios in IE.Rocketry
S
94
HttpContext.Current.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
HttpContext.Current.Response.Cache.SetValidUntilExpires(false);
HttpContext.Current.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
HttpContext.Current.Response.Cache.SetNoStore();

All requests get routed through default.aspx first - so assuming you can just pop in code behind there.

Supinate answered 21/7, 2009 at 16:0 Comment(8)
I would put it into Global.asax.cs in Application_BeginRequest(). I don't trust this default.aspx thing... Another question: does this have precedence over [OutputCache] attributes?Ilysa
I like the idea of simply creating a Global Action Filter an putting this stuff in that way. Negates the need to worry about Default.aspx and Global.asax.Gaudery
Putting this in Application_BeingRequest can cause some issues. If your images get routed through the .net runtime (which can happen if you're using wildcard mapping for nice urls) then no images will be cached on the browser. This can REALLY slow down your page load times as each page request will re-download all images.Traveller
Using anything programmatically will always override any declared Attribute. In other words, using the OP's code will override any declared [OutputCache] attribute.Utley
Any thoughts on how to smoke test and verify that the cache disable is actually working?Cody
Easiest smoke test would be to Logout and press your back button to see if the previous page (requiring authorization) renders or redirects you to login. A better test would be to use something like FireBug to review caching (you will see lots of 200 OK instead of 304 not modified in the Net panel)Electrokinetics
@herbrandson, where do you suggest this code is placed if not in the Application_BeginRequest()?Enamor
@MatthewT.Baker Unfortunately it's been a little while since I left this response (and since I worked on a .net web app) and I don't recall off hand where we had placed this logic. It seems like there are multiple options. It also partly depends on if you're using web forms or mvc. If you're using mvc, checkout out the answer from JKG for an example using an IActionFilter.Traveller
C
10

You may want to disable browser caching for all pages rendered by controllers (i.e. HTML pages), but keep caching in place for resources such as scripts, style sheets, and images. If you're using MVC4+ bundling and minification, you'll want to keep the default cache durations for scripts and stylesheets (very long durations, since the cache gets invalidated based on a change to a unique URL, not based on time).

In MVC4+, to disable browser caching across all controllers, but retain it for anything not served by a controller, add this to FilterConfig.RegisterGlobalFilters:

filters.Add(new DisableCache());

Define DisableCache as follows:

class DisableCache : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    }
}
Connolly answered 28/3, 2013 at 2:44 Comment(1)
Unfortunately this does not appear to work, as hitting the back button after a sign out displays the page.Enamor
B
6

I know this answer is not 100% related to the question, but it might help someone.

If you want to disable the browser cache for the entire ASP.NET MVC Website, but you only want to do this TEMPORARILY, then it is better to disable the cache in your browser.

Here's a screenshot in Chrome

Bailor answered 18/3, 2013 at 13:2 Comment(1)
This is exactly what I was looking for... during dev, if I change a .js file, it's a major pain to get that to come through immediately when I'm trouble to do little troubleshoot/refresh/test cycles. This is perfect, thank you! Just made my client side debugging life far easierPerianth
S
2

I implemented all the previous answers and still had one view that did not work correctly.

It turned out the name of the view I was having the problem with was named 'Recent'. Apparently this confused the Internet Explorer browser.

After I changed the view name (in the controller) to a different name (I chose to 'Recent5'), the solutions above started to work.

Sanbo answered 27/2, 2013 at 17:7 Comment(0)
D
0

You can try below code in Global.asax file.

protected void Application_BeginRequest()
    {
        Response.Cache.SetCacheability(HttpCacheability.NoCache);
        Response.Cache.SetExpires(DateTime.UtcNow.AddHours(-1));
        Response.Cache.SetNoStore();
    }
Dyann answered 8/11, 2017 at 9:19 Comment(0)
D
-1

UI

<%@ OutPutCache Location="None"%>
<%
    Response.Buffer = true;
    Response.Expires = -1;
    Response.ExpiresAbsolute = System.DateTime.Now.AddSeconds(-1);
    Response.CacheControl = "no-cache";
%>

Background

Context.Response.Cache.SetCacheability(HttpCacheability.NoCache); 
Response.Expires = -1;          
Response.Cache.SetNoStore();
Deferral answered 10/9, 2013 at 3:38 Comment(1)
needs explanatory prose, even if it is technically correctNihhi

© 2022 - 2024 — McMap. All rights reserved.