ASP.NET MVC 3中的OutputCache行为

kid*_*man 10 asp.net-mvc caching outputcache asp.net-mvc-3

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

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

public ActionResult View(UserViewCommand command) {
Run Code Online (Sandbox Code Playgroud)

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

这是我的OutputCache声明:

[HttpGet, OutputCache(Duration = 2000, VaryByParam = "None")]
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试使用不同的'slug'值(通过操作URL)来命中Action方法时,而不是提供错误的数据(我试图通过设计强制),而是调用action方法.

所以例如(按调用顺序)

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

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

kid*_*man 11

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

在最新版本(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团队(和古师傅)!你们都很棒!


Bui*_*ted 5

VaryByParam仅在url的值看起来有效时才有效/user/view?slug=abc.params必须是QueryString参数,而不像上面的示例那样是url的一部分.其原因很可能是因为缓存发生在任何url映射之前,并且该映射未包含在缓存中.

更新

以下代码将为您提供您想去的地方.它没有考虑像Authorized过滤器或任何东西,但它将基于控制器/动作/ ids缓存,但如果你设置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();
    }
}
Run Code Online (Sandbox Code Playgroud)