Вопрос

In my .NET code, I have a custom handler that process Http request and in the ProcessRequest Method calls a custom HttpModule to set Http Cache Headers.

The HttpModule sets the header in the PreSendRequestHeaders method with the following code

HttpCachePolicy cache = response.Cache;
if (cache != null)
{
  cache.SetCacheability(HttpCacheability.Public);
  cache.SetMaxAge(TimeSpan.FromSeconds(varnishDuration));
  response.AppendHeader("Edge-control", String.Concat("!no-store, max-age=", akamaiDuration, "s dca=noop"));
}

In IIS 7.5, with the pool in integrated mode, the CacheControl is forced to private. Here is what I got :

curl -IXGET -H "Host:myHostName" "http://myServer/mypage"
HTTP/1.1 200 OK
Cache-Control: private
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
Edge-control: !no-store, max-age=300s dca=noop
[...]

I don't understand why IIS changes the CacheControl to private.

Here is my webserver section in my web.config :

<pre>
<system.webServer>
    <handlers accessPolicy="Read, Script">
      <add name="OxygenHandler" verb="*" path="*" type="com.eurosport.oxygen.server.modules.OxygenHandlerFactory, OxygenServerModules" />
    </handlers>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="WebServiceCachingModule" type="com.eurosport.toolkit.WebServiceCachingModule, Eurosport.Toolkit" />
    </modules>
  </system.webServer>
</pre>

I tried to add SetSlidingExpiration as mentioned here Cache.SetMaxAge not working under IIS, works fine under VS Dev Srv but it did not help.

Это было полезно?

Решение

I've managed to get it working with the following code in my module :

response.Headers.Remove("Cache-Control");
response.AppendHeader("Cache-Control", "public, max-age=" + varnishDuration.ToString()+", s-max-age=" + varnishDuration.ToString());

It looks dirty but it seems that response.CacheControl and response.Cache properties are not used by IIS in integrated mode (or are overriden by some module...)

Другие советы

The default is specified in System.Web.HttpResponse.CacheControl:

        /// <devdoc>
        ///    <para>
        ///       Provided for ASP compatiblility. Use the <see cref='System.Web.HttpResponse.Cache'/>
        ///       property instead.
        ///    </para>
        /// </devdoc>
        public string CacheControl {
            get {
                if (_cacheControl == null) {
                    // the default
                    return "private";
                }

                return _cacheControl;
            }

While you can override the header through (global) filters, this doesn't work for error pages caused by authentication/authorization. Luckily there's a nice entry point for each request, allowing you to override this default:

// In Global.asax.cs:
        protected void Application_BeginRequest()
        {
            Context.Response.CacheControl = "no-cache";
        }

Update: Setting cache-control per above will disable caching of bundles. I'm now using the following workaround. It only changes the page's cacheability when it was not explicitly set. The default value of '6' comes from here:

// In Global.asax.cs:
        protected void Application_EndRequest()
        {
            if ((int)Response.Cache.GetCacheability() == ((int)HttpCacheability.ServerAndPrivate) + 1)
                Response.Cache.SetCacheability(HttpCacheability.NoCache);
        }

Furthermore when there's an error and the YSOD (yellow error page) is rendered through ReportRuntimeError, the framework will call ClearHeaders and your custom cache-control setting will be overridden. I haven't found a solution for this.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top