OutputCache mvc3 RemoveOutputCacheItem RenderAction

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

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

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

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

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

спасибо

2 ответов


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

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. затем, очевидно, введите возможность истечения срока действия кэшированной части пончика.

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

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