Поведение OutputCache в ASP.NET MVC 3 - PullRequest
10 голосов
/ 23 ноября 2010

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

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

public ActionResult View(UserViewCommand command) {

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

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

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

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

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

/ user / view / abc -> Вызывает метод действия с slug = abc / user / view / abc -> Метод действия не вызван / user / view / xyz -> Снова вызывает метод действия с slug = xyz! Разве он не должен был выходить из кэша, потому что VaryByParam = none?

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

Ответы [ 2 ]

11 голосов
/ 11 декабря 2010

Просто хотел добавить эту информацию, чтобы люди, ищущие, помогли:

В последнем выпуске поведение 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 (и Мастер Гу)! Вы все великолепны!

5 голосов
/ 23 ноября 2010

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

Обновление

Следующий код поможет вам достичь желаемого результата.Он не учитывает такие вещи, как 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();
    }
}
...