Поведение OutputCache в ASP.NET MVC 3

Я просто тестировал выходное кэширование в RC-сборке ASP.NET MVC 3.

Как бы то ни было, это не чтит свойство VaryByParam (точнее, я не уверен, что понимаю, что происходит):

public ActionResult View(UserViewCommand command) {

Здесь UserViewCommand имеет свойство slug, которое используется для поиска пользователя из базы данных.

Это мое объявление OutputCache:

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

Однако, когда я пытаюсь использовать метод Action, используя разные значения "slug" (путем манипулирования URL-адресом), вместо того, чтобы использовать неправильные данные (которые я пытаюсь применить по дизайну), вместо этого он вызывает метод действия.

Итак, например (в порядке вызова)

/user/view/abc → Вызывает метод действия с slug = abc /user/view/abc → Не активирован метод действий /user/view/xyz → снова вызывает метод действия с slug = xyz! Не предполагается ли оно выйти из кеша, потому что VaryByParam = none?

Кроме того, каков рекомендуемый способ OutputCaching в такой ситуации? (пример выше)

Ответ 2

VaryByParam работает только тогда, когда значения url выглядят как /user/view?slug=abc. Параметры должны быть параметром QueryString, а не частью URL-адреса, подобным приведенным выше примерам. Причина этого, скорее всего, связана с тем, что кеширование происходит до любого сопоставления url и что сопоставление не включено в кеш.

Update

Следующий код доставит вас туда, куда вы хотите отправиться. Он не принимает во внимание такие вещи, как фильтры Authorized или что-то еще, но он будет кэшировать на основе контроллера /action/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();
    }
}