Инвалидация страниц при изменениях сущностей с использованием настраиваемого ASP.NET OutputCacheProvider - PullRequest
1 голос
/ 09 ноября 2011

Мы проводим рефакторинг нашего сайта для использования внешнего кэша, и в качестве первого шага мы использовали пользовательский OutputCacheProvider. Во-первых, мы создали простого провайдера, который просто упаковывает MemoryCache, и обнаружили проблемы с тем, как мы управляем зависимостями.

У нас есть пользовательский OutputCacheAttribute, который добавляет дополнительную зависимость от ключа, чтобы иметь возможность сделать недействительным набор страниц при изменении определенных объектов, и для сохранения этой функции я вижу несколько вариантов:

  1. Удаление вручную CachedVary, который ASP.NET хранит в кэше, при условии, что ключом является "a2" + query". Кажется, это работает, но я не уверен насчет надежности.

  2. Добавьте ключи кэша, которые содержат массив страниц, которые должны быть удалены из кэша, после чего ключ удаляется, чтобы использовать функцию зависимости ключа внешнего кэша, если она у него есть. Этого должно быть достаточно, чтобы эмулировать используемую нами ключевую зависимость, но более сложным способом.

  3. Забудьте об этом, установите короткий период кэширования и дайте им истечь, не беспокоясь об этом.

  4. Сделайте наше собственное кэширование страниц и забудьте о кэше вывода ASP.NET, не очень привлекательном.

Я уверен, что есть другие способы. Любые советы, опыт или рекомендации?

1 Ответ

1 голос
/ 24 ноября 2011

Я отвечаю на свой вопрос с помощью решения, которое мы приняли только для протокола.

В нашем OutputCacheAttribute мы добавляем пустой объект кеша с ключом, который зависит от запрошенного URL и некоторых параметров. Это будет использоваться для внешней недействительности страницы.

Затем мы также добавляем еще один объект с ключом, который зависит от текущего запроса и содержит предыдущий cacheKey.

Наконец, устанавливается статический ValidationCallback. Обратный вызов получает значение ключа для текущего запроса, который является ключом зависимости. Затем, если оно не равно нулю, получает значение зависимости, если оно равно нулю, зависимость была удалена, и мы устанавливаем validationStatus в HttpValidationStatus.Invalid.

Код для иллюстрации:

public override void OnResultExecuting(ResultExecutingContext filterContext)
{
    base.OnResultExecuting(filterContext);

    // Build dependencies
    BuildDependencies(paramsToDepend, filterContext.Controller, this.Duration);
}

private void BuildDependencies(IEnumerable<string> paramsToDepend, ControllerBase controller, int duration)
{
    string[] valuesToInclude = GetValuesToInclude(paramsToInclude, controller.ControllerContext);

    // Build the caché key for the current request
    var cacheKey = CacheKeyProvider.GetCacheKeyFor(controller, paramsToDepend);

    var cache = controller.ControllerContext.HttpContext.Cache;
    var cacheValue = cache.Get(cacheKey);

    if (cacheValue == null)
    {
        // The key is created if not exists
        Provider.Add(cacheKey, new object(), Context.CurrentDateTime.AddSeconds(duration).ToUniversalTime());
    }

    // Add the dependency
    Provider.Set(CachePrefix + controller.ControllerContext.HttpContext.Request.Path, cacheKey, Context.CurrentDateTime.AddSeconds(duration).ToUniversalTime());

    // Register callback
    controller.ControllerContext.HttpContext.Response.Cache.AddValidationCallback(new HttpCacheValidateHandler(ValidationCallback), null);
}

public static void ValidationCallback(HttpContext context, object data, ref HttpValidationStatus validationStatus)
{
    var provider = OutputCache.Providers[OutputCache.DefaultProviderName];

    var dependency = provider.Get(CachePrefix + context.Request.RawUrl) as string;

    if (dependency == null) return;

    var depValue = provider.Get(dependency);

    // If it's null, someone has invelidated the caché (an entity was modified)
    if (depValue == null)
    {
        validationStatus = HttpValidationStatus.Invalid;
    }
}
...