覆盖ASP.NET缓存策略并将Cache-Control设置为public

时间:2015-04-23 13:57:43

标签: c# asp.net asp.net-mvc caching

我想在我的ASP.NET(MVC)应用中将Cache-Control标头设置为public。问题是以前设置缓存策略的代码(我无法改变):

        var response = htmlHelper.ViewContext.HttpContext.Response;
        response.Cache.SetExpires(System.DateTime.UtcNow.AddDays(-1));
        response.Cache.SetValidUntilExpires(false);
        response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
        response.Cache.SetCacheability(HttpCacheability.NoCache);
        response.Cache.SetNoStore();

我以后找不到覆盖它的方法,因为无论我如何尝试设置缓存控制,上面的内容都会生效。例如。以下两种方法都不能阻止先前禁用的缓存:

        httpContext.Response.Headers["Cache-Control"] = "public";
        var cache = httpContext.Response.Cache;
        cache.SetExpires(cacheItem.ValidUntilUtc);
        cache.SetValidUntilExpires(true);
        cache.SetRevalidation(HttpCacheRevalidation.None);
        cache.SetCacheability(HttpCacheability.Public);
        cache.SetMaxAge(cacheItem.ValidUntilUtc - _clock.UtcNow);

有没有办法以某种方式覆盖或重置缓存策略?

2 个答案:

答案 0 :(得分:3)

显然这不可能,因为HttpCachePolicy会主动阻止你设置更高的" cachability,即如果你设置NoCache后尝试设置Public,则不会发生任何事情。

似乎唯一的,hackish方式是使用私有反射并调用内部Reset方法如下:

        var cache = httpContext.Response.Cache;
        var cachePolicy = (HttpCachePolicy)typeof(HttpCachePolicyWrapper).InvokeMember("_httpCachePolicy", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField, null, cache, null);
        typeof(HttpCachePolicy).InvokeMember("Reset", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, cachePolicy, null);
        cache.SetCacheability(HttpCacheability.Public);

答案 1 :(得分:0)

在您的第一个代码示例中,看起来在HTML Helper中设置了缓存属性,这很可能是以某种方式在视图上呈现的。我猜你试图覆盖属性太早发生,然后被覆盖在视图的渲染上。

显然,更改设置这些标头的代码是最好的。如果你绝对不能,我会看到一些前进的路线:

  1. 不要立即从控制器返回视图。你可能有类似的东西:

    public ActionResult MyAction() {
        // code here
    
        return View();
    }
    

    将其转为,然后您可以尝试在视图中覆盖缓存:

    public ActionResult MyAction() {
        // code here
    
        var result = View();
        ResetCaching();
        return result;
    }
    
  2. 如果这不起作用,请在控制器中使用OnResultExecutedOnActionExecuted来捕获视图何时完成执行或操作已执行并尝试在视图后覆盖缓存和/或行动已经执行但在控制器处理之前。

    您可以实现custom action filter,而不是覆盖控制器上的实际事件,这可以使代码更清晰,并允许您在多个位置重复使用它。

  3. 绝对最坏的情况,请使用Application_PreSendRequestHeaders文件中的global.asax事件,如果请求符合重置缓存的要求,请在将标头发送到浏览器之前修改标头。此方法将使您检查通过应用程序的每个请求。