I am trying to make sure that a certain page is never cached, and never shown when the user clicks the back button. This very highly rated answer (currently 1068 upvotes) says to use:
Response.AppendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
Response.AppendHeader("Pragma", "no-cache");
Response.AppendHeader("Expires", "0");
However in IIS7 / ASP.NET MVC, when I send those headers then the client sees these response headers instead:
Cache-control: private, s-maxage=0 // that's not what I set them to
Pragma: no-cache
Expires: 0
What happened to the cache-control header? Does something native to IIS7 or ASP.NET overwrite it? I have checked my solution and I have no code that overwrites this header.
When I add Response.Headers.Remove("Cache-Control");
first, it makes no difference:
Response.Headers.Remove("Cache-Control");
Response.AppendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
Response.AppendHeader("Pragma", "no-cache");
Response.AppendHeader("Expires", "0");
When I add an [OutputCache]
attribute:
[OutputCache(Location = OutputCacheLocation.None)]
public ActionResult DoSomething()
{
Response.Headers.Remove("Cache-Control");
Response.AppendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
Response.AppendHeader("Pragma", "no-cache");
Response.AppendHeader("Expires", "0");
var model = DoSomething();
return View(model);
}
Then the client response headers change to:
Cache-control: no-cache
Pragma: no-cache
Expires: 0
Which is closer, but still not the headers that I want to send. Where are these headers getting overridden and how can I stop it?
EDIT: I have checked and the incorrect headers are being sent to Chrome, FF, IE and Safari, so it looks to be a server problem not a browser related problem.
If you need these headers globally in your MVC application. Add this class.
For global use add it to the FilterConfig.
Or only use these headers on a specific controller.
Side note: you can use IIS and web.config for other headers. For example on static content like your bundles (jquery,bootstrap). Look for these sections customheaders, staticcontent.
I want to add something to JK's answer:
If you are setting the cache control to a more restrictive value than it already is, it is fine. (i.e: setting no-cache, when it is private)
But, if you want to set to a less restrictive value than it already is (i.e: setting to private, when it is no-cache), the code below will not work:
Because, SetCacheablitiy method has this code below and sets the cache flag only if it is more restrictive:
To overcome this in .net mvc, you need to get an instance of HttpResponseMessage and assign a
CacheControlHeaderValue
to itsHeaders.CacheControl
value:An instance of the
HttpResponseMessage
is available in action filters. You can write an action filter to set cache header values like this:Through trial and error, I have found that one way to set the headers correctly for IIS7 in ASP.NET MVC is:
The first line sets
Cache-control
tono-cache
, and the second line adds the other attributesno-store, must-revalidate
.This may not be the only way, but does provide an alternative method if the more straightforward
Response.AppendHeader("Cache-control", "no-cache, no-store, must-revalidate");
fails.Other related IIS7 cache-control questions that may be solved by this are: