7

I'm having trouble using the OutputCache attribute in Microsoft's MVC3 framework.

Please imagine the following controller action, which can be used as part of an AJAX call to get a list of products based on a particular manufacturerId:

public JsonResult GetProducts(long manufacturerId)
{
    return Json(this.CreateProductList(manufacturerId), JsonRequestBehavior.AllowGet);
}

I want this result to be cached on the server to avoid making excessive database queries. I can achieve this by configuring the attribute thus:

[OutputCache(Duration = 3600, Location = OutputCacheLocation.Server, VaryByParam = "manufacturerId")]

This works as I expected - the browser makes an intitial request which causes the server to create and cache the result, subsequent requests from the same or different browser get the cached version.

But... I also want the browser to cache these results locally; if I filter first on manufacturer X, then Y then go back to X, I don't want it to make another request for X's products - I want it to just use its cached version.

I can make this happen, by changing the OutputCache to this:

[OutputCache(Duration = 3600, Location = OutputCacheLocation.Client)]

Here's the question: how do I combine these so that I can have both sets of behaviour? I tried setting the Location to ServerAndClient but this just made it behave the same as when Location was Server.

I'm sure that the problem has something to do with the "Vary: *" response header I get with ServerAndClient but I don't know how to get rid of it.

I welcome comments about the rationality of my intentions - the fact that I'm not getting the results I expect makes me think I might have some fundamental misunderstanding somewhere...

Many thanks.

PS: This is on a local dev environment, IIS Express from VS2010.

Adam Brown
  • 332
  • 3
  • 10

1 Answers1

8

You can use OutputCacheLocation.Any which specifies

The output cache can be located on the browser client (where the request originated), on a proxy server (or any other server) participating in the request, or on the server where the request was processed. This value corresponds to the HttpCacheability.Public enumeration value.

You may want to also set Cache-control public to in the HTTP header for these requests.

Edit

It seems, depending on your .Net version of the web server you may need to include Response.Cache.SetOmitVaryStar(true); within your controller action to remove the Vary * headers as you suggest.

Details of the reason why in .Net 4 breaking changes release notes.

AlexC
  • 10,676
  • 4
  • 37
  • 55
  • Thanks Alex but I'm afraid this still has the same effect as setting it to "Server"; the client still makes a request and just gets the cached version. I'm looking at the headers in fiddler and it seems that whenever I include anything other than Client in Location, I get "Vary: *" in the response header which causes the browser to ignore its local cache... – Adam Brown Aug 21 '12 at 09:59
  • Is this on a real IIS box or a dev machine? – AlexC Aug 21 '12 at 10:07
  • 1
    Oh sorry, I forgot to add that: it's a dev environment, IIS Express from VS2010 – Adam Brown Aug 21 '12 at 11:50
  • Thank you! `Response.Cache.SetOmitVaryStar(true);` did the trick. It now works just how I wanted it to. – Adam Brown Aug 21 '12 at 11:55