mvc3 OutputCache RemoveOutputCacheItem RenderAction - PullRequest
7 голосов
/ 16 марта 2011

Я провел исследование, но не нашел ответов.

Я использую Html.RenderAction на главной странице (для отображения заголовка страницы со ссылками, относящимися к разрешениям пользователя). Действие оформлено с помощью OutputCache, возвращает частичное управление и кэшируется, как ожидается.

Когда происходит событие (скажем, разрешения изменены), я хочу программно аннулировать частичный элемент управления в кэше.

Я пытаюсь использовать метод RemoveOutputCacheItem. Он принимает путь в качестве параметра. Я пытаюсь установить путь к действию, используемому в Html.RenderAction. Это не делает действие недействительным.

Как программно аннулировать действие?

Спасибо

Ответы [ 2 ]

9 голосов
/ 16 марта 2011

Кэш для дочерних действий хранится в свойстве OutputCacheAttribute.ChildActionCache . Проблема заключается в том, что API, генерирующий идентификаторы для дочерних действий и сохраняющий их в этом объекте, не является общедоступным (ПОЧЕМУ Microsoft ??). Поэтому, если вы попытаетесь перебрать объекты в этой коллекции, вы обнаружите, что она также будет содержать кэшированное значение для вашего дочернего действия, но вы не сможете его идентифицировать, если не перепроектируете алгоритм, используемый для генерации ключей, которые выглядят как-то так (как видно с помощью Reflector):

internal string GetChildActionUniqueId(ActionExecutingContext filterContext)
{
    StringBuilder builder = new StringBuilder();
    builder.Append("_MvcChildActionCache_");
    builder.Append(filterContext.ActionDescriptor.UniqueId);
    builder.Append(DescriptorUtil.CreateUniqueId(new object[] { this.VaryByCustom }));
    if (!string.IsNullOrEmpty(this.VaryByCustom))
    {
        string varyByCustomString = filterContext.HttpContext.ApplicationInstance.GetVaryByCustomString(HttpContext.Current, this.VaryByCustom);
        builder.Append(varyByCustomString);
    }
    builder.Append(GetUniqueIdFromActionParameters(filterContext, SplitVaryByParam(this.VaryByParam)));
    using (SHA256 sha = SHA256.Create())
    {
        return Convert.ToBase64String(sha.ComputeHash(Encoding.UTF8.GetBytes(builder.ToString())));
    }
}

Чтобы вы могли совершить следующее безумие:

public ActionResult Invalidate()
{
    OutputCacheAttribute.ChildActionCache = new MemoryCache("NewDefault");
    return View();
}

, который, очевидно, сделает недействительными все кэшированные дочерние действия, которые могут быть не тем, что вы ищете, но, боюсь, это единственный способ, кроме, конечно, обратного инжиниринга генерации ключей: -).

@ Microsoft, прошу вас попросить ASP.NET MVC 4.0:

  1. вводит возможность делать кэширование пончиков в дополнение к кэшированию дырок от пончиков
  2. предоставляет возможность легкого истечения срока действия кэшированного контроллера (что-то более MVCish, чем Response.RemoveOutputCacheItem)
  3. предоставляет возможность легкого истечения срока действия кэшированного дочернего действия
  4. если вы выполните 1., тогда, очевидно, представьте возможность истечения срока хранения кэшированной части пончика.
2 голосов
/ 16 марта 2011

Возможно, вы захотите подойти к этому по-другому.Вы можете создать собственный AuthorizeAttribute - он просто позволит всем - и добавить переопределить метод OnCacheValidation, чтобы включить вашу логику.Если базовый OnCacheValidation возвращает HttpValidationStatus.Valid, проверьте, изменилось ли состояние, и если да, вместо этого верните HttpValidationStatus.Invalid.

public class PermissionsChangeValidationAttribute : AuthorizeAttribute
{
     public override OnAuthorization( AuthorizationContext filterContext )
     {
        base.OnAuthorization( filterContext );
     }

     public override HttpValidationStatus OnCacheAuthorization( HttpContextBase httpContext )
     {
         var status = base.OnCacheAuthorization( httpContext );
         if (status == HttpValidationStatus.Valid)
         {
            ... check if the permissions have changed somehow
            if (changed)
            {
                status = HttpValidationStatus.Invalid;
            }
         }
         return status;
     }
}

Обратите внимание, что существуют способы передачи дополнительных данных впроцесс проверки кэша, если вам нужно отслеживать предыдущее состояние, но вам нужно будет скопировать некоторый код в базовом классе и добавить свой собственный обработчик проверки кэша.Некоторые идеи о том, как это сделать, можно найти в моем блоге о создании пользовательского атрибута авторизации: http://farm -fresh-code.blogspot.com / 2011/03 / revisiting-custom-authorization-in.html

...