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) s
Through trial and error, I have found that one way to set the headers correctly for IIS7 in ASP.NET MVC is:
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.AppendCacheExtension("no-store, must-revalidate");
Response.AppendHeader("Pragma", "no-cache");
Response.AppendHeader("Expires", "0");
The first line sets Cache-control
to no-cache
, and the second line adds the other attributes no-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:
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:
Response.Cache.SetCacheability(HttpCacheability.Private);
Because, SetCacheablitiy method has this code below and sets the cache flag only if it is more restrictive:
if (s_cacheabilityValues[(int)cacheability] < s_cacheabilityValues[(int)_cacheability]) {
Dirtied();
_cacheability = cacheability;
}
To overcome this in .net mvc, you need to get an instance of HttpResponseMessage and assign a CacheControlHeaderValue
to its Headers.CacheControl
value:
actionExecutedContext.Response.Headers.CacheControl = new CacheControlHeaderValue
{
MaxAge = TimeSpan.FromSeconds(3600),
Private = true
};
An instance of the HttpResponseMessage
is available in action filters. You can write an action filter to set cache header values like this:
public class ClientSideCacheAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var response = actionExecutedContext.ActionContext.Response;
response.Headers.CacheControl = new System.Net.Http.Headers.CacheControlHeaderValue
{
MaxAge = TimeSpan.FromSeconds(9999),
Private = true,
};
}
}
If you need these headers globally in your MVC application. Add this class.
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class CustomHeaders : System.Web.Mvc.ActionFilterAttribute
{
[OutputCache(Location = System.Web.UI.OutputCacheLocation.None)]
public override void OnActionExecuted(ActionExecutedContext context)
{
context.RequestContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
context.RequestContext.HttpContext.Response.Cache.AppendCacheExtension("no-store, must-revalidate");
context.RequestContext.HttpContext.Response.AppendHeader("Pragma", "no-cache");
context.RequestContext.HttpContext.Response.AppendHeader("Expires", "0");
base.OnActionExecuted(context);
}
}
For global use add it to the FilterConfig.
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new CustomHeaders());
}
}
Or only use these headers on a specific controller.
[Authorize]
[CustomHeaders]
public class HomeController : Controller
{
[AllowAnonymous]
public ActionResult Index()
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.