205

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.

1

9 Answers 9

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();
    }
}
Sign up to request clarification or add additional context in comments.

18 Comments

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.
IActionFilter is already implemented on the ActionFilterAttribute, so you don't need to repeat it.
In current versions of ASP.NET MVC you can simply use OutputCacheAttribute to prevent caching: [OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")]
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...
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.
|
133

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()
{
  ...
}

12 Comments

@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.
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.
+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."
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.
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.
|
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.

8 Comments

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?
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.
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.
Using anything programmatically will always override any declared Attribute. In other words, using the OP's code will override any declared [OutputCache] attribute.
Any thoughts on how to smoke test and verify that the cache disable is actually working?
|
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);
    }
}

1 Comment

Unfortunately this does not appear to work, as hitting the back button after a sign out displays the page.
7

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

1 Comment

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 easier
3

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.

Comments

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();
    }

1 Comment

I found this answer did not work for static resources (images, css, js).
0

You can also add the headers to the web.config file:

<configuration>
    <system.webServer>
        <httpProtocol>
            <customHeaders>
                <add name="Cache-Control" value="no-cache"/>
            </customHeaders>
        </httpProtocol>
    </system.webServer>
</configuration>

This will apply to every request.

Thanks to https://stackoverflow.com/a/34393611/159347 for providing this answer.

Comments

-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();

1 Comment

needs explanatory prose, even if it is technically correct

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.