【问题标题】:OutputCache behavior in ASP.NET MVC 3ASP.NET MVC 3 中的 OutputCache 行为
【发布时间】:2011-05-14 12:40:27
【问题描述】:

我只是在 ASP.NET MVC 3 的 RC 版本中测试输出缓存。

不知何故,它不尊重 VaryByParam 属性(或者更确切地说,我不确定我是否理解发生了什么):

public ActionResult View(UserViewCommand command) {

这里,UserViewCommand 有一个名为 slug 的属性,用于从数据库中查找用户。

这是我的 OutputCache 声明:

[HttpGet, OutputCache(Duration = 2000, VaryByParam = "None")]

但是,当我尝试使用不同的“slug”值(通过操纵 URL)点击 Action 方法时,它不是提供错误数据(我试图通过设计强制),而是调用 action 方法。

例如(按调用顺序)

/user/view/abc -> 使用 slug = abc 调用操作方法 /user/view/abc -> 未调用操作方法 /user/view/xyz -> 再次使用 slug = xyz 调用操作方法!它不应该因为 VaryByParam = none 而从缓存中出来吗?

另外,在这种情况下,推荐的 OutputCaching 方式是什么? (上例)

【问题讨论】:

    标签: asp.net-mvc caching asp.net-mvc-3 outputcache


    【解决方案1】:

    只是想添加此信息,以便帮助人们搜索:

    在最新版本 (ASP.NET MVC 3 RC 2) 中,OutputCache 行为已更改为“符合预期”:

    http://weblogs.asp.net/scottgu/archive/2010/12/10/announcing-asp-net-mvc-3-release-candidate-2.aspx

    ASP.NET MVC 团队(和顾大师)前进的道路!你们都很棒!

    【讨论】:

      【解决方案2】:

      VaryByParam 仅在 url 的值类似于 /user/view?slug=abc 时有效。参数必须是 QueryString 参数,而不是像上面的示例一样的 url 的一部分。造成这种情况的原因很可能是因为缓存发生在任何 url 映射之前,并且该映射不包含在缓存中。

      更新

      以下代码将带您到达您想去的地方。它不考虑Authorized过滤器之类的东西,但它会根据控制器/动作/ID进行缓存,但如果你设置了ignore="slug",它将忽略该特定属性

      public class ActionOutputCacheAttribute : ActionFilterAttribute {
          public ActionOutputCacheAttribute(int cacheDuration, string ignore) {
              this.cacheDuration = cacheDuration;
              this.ignore = ignore;
          }
      
          private int cacheDuration;
          private string cacheKey;
          private string ignore;
      
          public override void OnActionExecuting(ActionExecutingContext filterContext) {
              string url = filterContext.HttpContext.Request.Url.PathAndQuery;
              this.cacheKey = ComputeCacheKey(filterContext);
      
              if (filterContext.HttpContext.Cache[this.cacheKey] != null) {
                  //Setting the result prevents the action itself to be executed
                  filterContext.Result =
                  (ActionResult)filterContext.HttpContext.Cache[this.cacheKey];
              }
      
              base.OnActionExecuting(filterContext);
          }
      
          public override void OnActionExecuted(ActionExecutedContext filterContext) {
              //Add the ActionResult to cache 
              filterContext.HttpContext.Cache.Add(this.cacheKey, filterContext.Result,null, DateTime.Now.AddSeconds(cacheDuration),
                System.Web.Caching.Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
      
              //Add a value in order to know the last time it was cached.
              filterContext.Controller.ViewData["CachedStamp"] = DateTime.Now;
      
              base.OnActionExecuted(filterContext);
          }
      
          private string ComputeCacheKey(ActionExecutingContext filterContext) {
              var keyBuilder = new StringBuilder();
              keyBuilder.Append(filterContext.ActionDescriptor.ControllerDescriptor.ControllerName);
              keyBuilder.Append(filterContext.ActionDescriptor.ActionName);
      
              foreach (var pair in filterContext.RouteData.Values) {
                  if (pair.Key != ignore) 
                      keyBuilder.AppendFormat("rd{0}_{1}_", pair.Key.GetHashCode(), pair.Value.GetHashCode());
              }
              return keyBuilder.ToString();
          }
      }
      

      【讨论】:

      • 但我什至没有在 VaryByParam 属性中指定“slug”参数。既然它实际上没有检查“slug”,我不应该得到相同的结果吗?还是它也依赖于请求的 URL?
      • 正确,但此处的 None 仅适用于 QueryString 值 - 整个 VaryByParam 选项仅适用于 QueryStringValues。我只是以你的蛞蝓为例:)
      • 所以如果我没看错,缓存会因请求 URL 而异? OutputCache(至少在 MVC 中的实现)不支持这种情况似乎很奇怪。还是我们错过了什么?
      • 有一个很好的方法可以做到这一点......现在就寻找它。
      猜你喜欢
      • 1970-01-01
      • 2018-02-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多