mvc3 OutputCache RemoveOutputCacheItem RenderAction

时间:2011-03-16 13:45:22

标签: asp.net-mvc-3 outputcache

我做了我的研究,但没有找到任何答案。

我在母版页中使用Html.RenderAction(使用特定于用户权限的链接呈现页眉)。 Action使用OutputCache进行修饰,返回部分控制并按预期缓存。

当事件发生时(假设权限已更改)我想以编程方式使缓存的部分控件无效。

我正在尝试使用RemoveOutputCacheItem方法。它将路径作为参数。我正在尝试设置Html.RenderAction中使用的操作的路径。这并不会使行动无效。

如何以编程方式使操作无效?

由于

2 个答案:

答案 0 :(得分:9)

子操作的缓存存储在OutputCacheAttribute.ChildActionCache属性中。问题是,为子操作生成ID并将其存储在此对象中的API不是公共的(为什么是Microsoft?)。因此,如果您尝试遍历此集合中的对象,您将发现它还将包含子操作的缓存值,但除非您反向设计用于生成看起来的键的算法,否则您将无法识别它像这样的东西(用Reflector看到):

internal string GetChildActionUniqueId(ActionExecutingContext filterContext)
{
    StringBuilder builder = new StringBuilder();
    builder.Append("_MvcChildActionCache_");
    builder.Append(filterContext.ActionDescriptor.UniqueId);
    builder.Append(DescriptorUtil.CreateUniqueId(new object[] { this.VaryByCustom }));
    if (!string.IsNullOrEmpty(this.VaryByCustom))
    {
        string varyByCustomString = filterContext.HttpContext.ApplicationInstance.GetVaryByCustomString(HttpContext.Current, this.VaryByCustom);
        builder.Append(varyByCustomString);
    }
    builder.Append(GetUniqueIdFromActionParameters(filterContext, SplitVaryByParam(this.VaryByParam)));
    using (SHA256 sha = SHA256.Create())
    {
        return Convert.ToBase64String(sha.ComputeHash(Encoding.UTF8.GetBytes(builder.ToString())));
    }
}

所以你可以执行以下疯狂:

public ActionResult Invalidate()
{
    OutputCacheAttribute.ChildActionCache = new MemoryCache("NewDefault");
    return View();
}

这显然会使所有缓存的子操作无效,这些操作可能不是您正在寻找的但我担心除了当然是对密钥生成进行逆向工程之外的唯一方法: - )。

@Microsoft,拜托,我求你参加ASP.NET MVC 4.0:

  1. 介绍除甜甜圈洞缓存外还可以进行甜甜圈缓存
  2. 介绍了轻松过期缓存控制器操作结果的可能性(MVCish比Response.RemoveOutputCacheItem更多)
  3. 介绍了轻松过期缓存子操作的结果的可能性
  4. 如果你这样做1.那么显然有可能使缓存的甜甜圈部分到期。

答案 1 :(得分:2)

您可能希望以不同的方式处理此问题。您可以创建一个自定义AuthorizeAttribute - 它只是允许每个人 - 并添加覆盖OnCacheValidation方法以合并您的逻辑。如果基础OnCacheValidation返回HttpValidationStatus.Valid,那么请检查状态是否已更改,如果是,则返回HttpValidationStatus.Invalid。

public class PermissionsChangeValidationAttribute : AuthorizeAttribute
{
     public override OnAuthorization( AuthorizationContext filterContext )
     {
        base.OnAuthorization( filterContext );
     }

     public override HttpValidationStatus OnCacheAuthorization( HttpContextBase httpContext )
     {
         var status = base.OnCacheAuthorization( httpContext );
         if (status == HttpValidationStatus.Valid)
         {
            ... check if the permissions have changed somehow
            if (changed)
            {
                status = HttpValidationStatus.Invalid;
            }
         }
         return status;
     }
}

请注意,如果需要跟踪以前的状态,可以在缓存验证过程中传递其他数据,但是您必须在基类中复制一些代码并添加自己的自定义缓存验证处理程序。您可以从我关于创建自定义授权属性的博客文章中了解如何执行此操作的一些想法:http://farm-fresh-code.blogspot.com/2011/03/revisiting-custom-authorization-in.html