6

I am experiencing a problem with IE caching the results of an action method.

Other articles I found were related to security and the [Authorize] attribute. This problem has nothing to do with security.

This is a very simple "record a vote, grab the average, return the avg and the number of votes" method. The only slightly interesting thing about it is that it is invoked via Ajax and returns a Json object. I believe that it is the Json object that is getting cached.

When I run it from FireFox and watch the XHR traffic with Firebug, everything works perfectly. However, under IE 8 the "throbber" graphic doesn't ever have time to show up and the page elements that display the "new" avg and count that are being injected into the page with jQuery are never different.

I need a way to tell MVC to never cache this action method.

This article seems to address the problem, but I cannot understand it: Prevent Caching of Attributes in ASP.NET MVC, force Attribute Execution every time an Action is Executed

I need a bit more context for the solution to understand how to extend AuthorizationAttribute. Please address your answer as if you were speaking to someone who lacks a deep understanding of MVC even if that means replying with an article on some basics/prerequisites that are required.

Thanks,

Trey Carroll

Community
  • 1
  • 1
Trey Carroll
  • 2,332
  • 4
  • 22
  • 28

1 Answers1

21

MVC doesn't cache the results. IE does.

So you have to tell IE not to do it.

Here's how I do it. First, an attribute:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public sealed class CacheControlAttribute : ActionFilterAttribute
{
    public CacheControlAttribute(HttpCacheability cacheability)
    {
        this._cacheability = cacheability;
    }

    public HttpCacheability Cacheability { get { return this._cacheability; } } 

    private HttpCacheability _cacheability;

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache;
        cache.SetCacheability(_cacheability);
    }
}

Next, an action:

    [CacheControl(HttpCacheability.NoCache), HttpGet]
    public JsonResult MyAction()
Craig Stuntz
  • 123,797
  • 12
  • 247
  • 268
  • Thank you Craig. This is exactly what I needed. I just added the class to the Root Level of the MVC project, however, which I'm sure is incorrect. What would be the correct location for this class in an MVC 2 solution? – Trey Carroll Jun 10 '10 at 03:59
  • Up to you. This is, effectively, framework code. You can put it in a separate class library or an "Mvc" namespace in your web app. – Craig Stuntz Jun 10 '10 at 12:07
  • 3
    This is much simpler in MVC now, just use OutputCache and set duration to zero seconds: [OutputCache(Duration = 0)] public ActionResult Cities(int provinceId) { var myData = SomeClassInstance.SomeMethod(); return Json(myData, JsonRequestBehavior.AllowGet); } – Tore Aurstad May 03 '12 at 16:00
  • 3
    @ToreAurstad: That's not quite the same. You might want the server to cache the results, but the browser to not cache the results. – Craig Stuntz May 03 '12 at 17:52
  • @CraigStuntz so are you saying that with your solution, one can still have the server cache the result (by using OutputCache with a meaningful duration) and still have the browser NOT cache the result (with your CacheControl attribute)? – Shawn de Wet Nov 28 '12 at 01:47
  • @ShawndeWet, yes, you can do that. – Craig Stuntz Nov 28 '12 at 13:12
  • 1
    @ToreAurstad Your solution was the only one that worked for me. Did try several solutions. – Andreas Sep 18 '13 at 07:19