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

Override ASP.NET cache policy and set Cache-Control to public

我想在我的 ASP.NET (MVC) 应用程序中将 Cache-Control header 设置为 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);

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

在您的第一个代码示例中,缓存属性似乎是在 HTML 帮助程序中设置的,它很可能以某种方式呈现在视图上。我猜你试图覆盖属性发生得太早,然后在视图的渲染中被覆盖。

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

  1. 不要return 立即从控制器查看。你可能有这样的东西:

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

    将其转换为这样您就可以尝试覆盖视图中的缓存:

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

    您可以实现一个 custom action filter,而不是覆盖控制器上的实际事件,这可以使代码更简洁并允许您在多个地方重用它。

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

显然这不可能,因为 HttpCachePolicy 会主动阻止您设置 "higher" 可缓​​存性,即如果您在设置 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);