Prevent Caching in ASP.NET MVC for specific actions using an attribute

191,273

Solution 1

To ensure that JQuery isn't caching the results, on your ajax methods, put the following:

$.ajax({
    cache: false
    //rest of your ajax setup
});

Or to prevent caching in MVC, we created our own attribute, you could do the same. Here's our code:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed 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 just decorate your controller with [NoCache]. OR to do it for all you could just put the attribute on the class of the base class that you inherit your controllers from (if you have one) like we have here:

[NoCache]
public class ControllerBase : Controller, IControllerBase

You can also decorate some of the actions with this attribute if you need them to be non-cacheable, instead of decorating the whole controller.

If your class or action didn't have NoCache when it was rendered in your browser and you want to check it's working, remember that after compiling the changes you need to do a "hard refresh" (Ctrl+F5) in your browser. Until you do so, your browser will keep the old cached version, and won't refresh it with a "normal refresh" (F5).

Solution 2

You can use the built in cache attribute to prevent caching.

For .net Framework: [OutputCache(NoStore = true, Duration = 0)]

For .net Core: [ResponseCache(NoStore = true, Duration = 0)]

Be aware that it is impossible to force the browser to disable caching. The best you can do is provide suggestions that most browsers will honor, usually in the form of headers or meta tags. This decorator attribute will disable server caching and also add this header: Cache-Control: public, no-store, max-age=0. It does not add meta tags. If desired, those can be added manually in the view.

Additionally, JQuery and other client frameworks will attempt to trick the browser into not using it's cached version of a resource by adding stuff to the url, like a timestamp or GUID. This is effective in making the browser ask for the resource again but doesn't really prevent caching.

On a final note. You should be aware that resources can also be cached in between the server and client. ISP's, proxies, and other network devices also cache resources and they often use internal rules without looking at the actual resource. There isn't much you can do about these. The good news is that they typically cache for shorter time frames, like seconds or minutes.

Solution 3

All you need is:

[OutputCache(Duration=0)]
public JsonResult MyAction(

or, if you want to disable it for an entire Controller:

[OutputCache(Duration=0)]
public class MyController

Despite the debate in comments here, this is enough to disable browser caching - this causes ASP.Net to emit response headers that tell the browser the document expires immediately:

OutputCache Duration=0 Response Headers: max-age=0, s-maxage=0

Solution 4

In the controller action append to the header the following lines

    public ActionResult Create(string PositionID)
    {
        Response.AppendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
        Response.AppendHeader("Pragma", "no-cache"); // HTTP 1.0.
        Response.AppendHeader("Expires", "0"); // Proxies.

Solution 5

Here's the NoCache attribute proposed by mattytommo, simplified by using the information from Chris Moschini's answer:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class NoCacheAttribute : OutputCacheAttribute
{
    public NoCacheAttribute()
    {
        this.Duration = 0;
    }
}
Share:
191,273

Related videos on Youtube

JavaScript Developer
Author by

JavaScript Developer

Updated on July 31, 2020

Comments

  • JavaScript Developer
    JavaScript Developer almost 4 years

    I have an ASP.NET MVC 3 application. This application requests records through jQuery. jQuery calls back to a controller action that returns results in JSON format. I have not been able to prove this, but I'm concerned that my data may be getting cached.

    I only want the caching to be applied to specific actions, not for all actions.

    Is there an attribute that I can put on an action to ensure that the data does not get cached? If not, how do I ensure that the browser gets a new set of records each time, instead of a cached set?

  • Obi Wan
    Obi Wan over 10 years
    I tried everything in the above solution and it does not work for me.
  • Josh
    Josh over 10 years
    It's my understanding (and I'm no jQuery expert) that cache:false only makes jQuery tack on to the query string a changing value to "trick" the browser into thinking the request is for something else. In theory, this means the browser would still cache the results, just wouldn't use the cached results. Should be more efficient on the client to disable caching via response headers.
  • Jaguir
    Jaguir almost 10 years
    It is impossible to force the browser to disable caching. The best you can do is provide suggestions that most browsers will honor, usually in the form of headers or meta tags. This decorator attribute will disable the .NET server caching and also add the header Cache-Control:public, no-store, max-age=0. It does not add meta tags. If desired, those can be added manually in the view.
  • Ramesh
    Ramesh over 9 years
    Worked only on controller level and not on action level.
  • Keith Ketterer
    Keith Ketterer about 9 years
    IE8 still renders the cached version of the page when the back button is clicked using only Duration=0 on a Controller Action. Using NoStore = true along with Duration = 0 (see Jared's answer) fixed the behavior in my case.
  • micahhoover
    micahhoover about 9 years
    For some reason MVC 3 doesn't just let you set the duration to 0. You have to add these annotations ... thanks for the workaround!
  • ta.speot.is
    ta.speot.is about 9 years
    This has the somewhat curious behavior of setting Cache-Control to public
  • Gone Coding
    Gone Coding about 9 years
    I can understand why you would use NoStore = true and Duration = 0 (which I have used successfully, thanks), but what additional effect would VaryByParam = "None" have as the other two options affect all requests regardless of parameter?
  • Jaguir
    Jaguir about 9 years
    I don't think it's required in MVC, I was just being explicit. I do remember that in ASP.NET web forms and user controls, either this attribute or the VaryByControl attribute is required.
  • Mark Rucker
    Mark Rucker almost 9 years
    Warning, I've been messing with this today. From what I can tell this attribute does not modify Cache-Control if <outputCache enableOutputCache="false" />. In the case that OutputCache has been explicitly disabled you'll need to set the CacheControl headers manually (either in the Action or by using [mattytommo's answer][stackoverflow.com/a/10011896/1066291]).
  • usr-local-ΕΨΗΕΛΩΝ
    usr-local-ΕΨΗΕΛΩΝ almost 9 years
    I would upvote including such an attribute in the official ASP.NET package :-)
  • Ted Nyberg
    Ted Nyberg over 8 years
    @usr-local-ΕΨΗΕΛΩΝ There is no need for such an attribute, see other answers involving OutputCache attribute instead.
  • mattytommo
    mattytommo over 8 years
    @TedNyberg See the last comment on the other answer from Mark Rucker, the built in attribute doesn't offer complete cache disabling.
  • Frédéric
    Frédéric over 8 years
    max-age=0 has never meant 'cache disabled'. This does only mean that response content is to be considered immediately stale, but a cache is allowed to cache it. Browsers should validate freshness of cached stale content before using it, but it is not mandatory unless the additional directive must-revalidate is specified.
  • Frédéric
    Frédéric over 8 years
    no-store is not guaranteed to be enough. The response may still be cached in a volatile cache (as ram memory). max-age=0 is neither sufficient alone or with no-store. It does not prevent caching, it just mark the content as immediately stale. It may still be cached, but caches are invited to revalidates it before use (but are allowed to serve it without revalidation).
  • Frédéric
    Frédéric over 8 years
    max-age=0 has never meant 'cache disabled'. This does only mean that response content is to be considered immediately stale, but a cache is allowed to cache it. Browsers should validate freshness of cached stale content before using it, but it is not mandatory unless the additional directive must-revalidate is specified.
  • Frédéric
    Frédéric over 8 years
    @TedNyberg, OutputCache does mix http cache control with server output cache (especially with it vary handling), does not honor the full semantics of http caching and does allow real deactivation of http caching (no-cache directive) by specifying Location=OutputCacheLocation.None (or Server). In short, outputcache is plainly broken when it is about http caching. We should only use it for controlling server output caching (which is broken by itself on IIS for loads of other reasons anyway).
  • Frédéric
    Frédéric over 8 years
    For completeness, the minimal and more appropriate directive is no-cache, which still allows caching but mandate to revalidates on origin server before any use. To avoid even revalidated caching you have to add no-store along with no-cache. (no-store alone is plainly wrong because volatile caches are allowed to cache content marked as no-store.)
  • Sam
    Sam over 8 years
    Pity it does not even compile with asp.net 5 :(
  • mattytommo
    mattytommo over 8 years
    @Sam Really? I haven't tried yet. What's the issue?
  • Sam
    Sam over 8 years
    @mattytommo No worries, I used [ResponseCache(NoStore = true)] instead, it works like charm and is build-in.
  • Frédéric
    Frédéric over 8 years
    See other comments (1, 2, 3) on the numerous answers already suggesting using this. Your second line is wrong and will lead to issues with some browsers.
  • Frédéric
    Frédéric over 8 years
    @Sam no-store alone is wrong because volatile caches are allowed by http spec to cache content marked as no-store. You may have issues in some browsers.
  • Sam
    Sam over 8 years
    @Frédéric what is recommended instead of using NoStore?
  • Frédéric
    Frédéric over 8 years
    @Sam, no-cache. But OutputCache does not allow to control it directly, you have to use Location with OutputCacheLocation value None or Server. This still does not really forbid caching, but it forces the client to at least check with the server its cached response is still valid.
  • kristianp
    kristianp over 7 years
    @Frédéric, the section of the spec you point to says that caches cannot cache no-store content: The "no-store" response directive indicates that a cache MUST NOT store any part of either the immediate request or response.
  • SAR
    SAR over 7 years
    @Jaguire for example i need to disable for the login page, do i need to place in account controller head or in each and every action or where!?
  • Jaguir
    Jaguir over 7 years
    @SAR Placing it on your login controller or its actions should suffice.
  • SAR
    SAR over 7 years
    @Jaguire i did put the code on top of the Account Controller which login is located there, again in google chrome i login and with out loging out i close the IE then again when i try IE i get the page with request for login
  • Jaguir
    Jaguir over 7 years
    @SAR That sounds like your issue is beyond simple caching. Maybe with your session or cookies? Start a question detailing your issue and you will get better help.
  • Jeff
    Jeff almost 7 years
    For ASP.NET Core use: '[ResponseCache(NoStore = true, Duration = 0)]'