Поведение 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 в такой ситуации? (пример выше)
Ответы
Ответ 1
Просто хотел добавить эту информацию, чтобы помочь людям:
Поведение OutputCache было изменено как "как ожидалось" в последней версии (ASP.NET MVC 3 RC 2):
http://weblogs.asp.net/scottgu/archive/2010/12/10/announcing-asp-net-mvc-3-release-candidate-2.aspx
Путь к выполнению команды ASP.NET MVC (и Master Gu)! Вы все потрясающие!
Ответ 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();
}
}