使用ASP.NET自定义OutputCacheProvider在实体更改时使页面无效

时间:2011-11-09 13:25:04

标签: asp.net outputcache

我们正在重构我们的网站以使用外部缓存,我们采取的第一步是使用自定义OutputCacheProvider。首先,我们创建了一个简单的提供程序,它只包含MemoryCache,并发现我们管理依赖项的方式存在问题。

我们有一个自定义OutputCacheAttribute,它添加了一个额外的密钥依赖项,以便在某些实体更改时能够使一组页面无效,并保留此功能,我看到了一些选项:

  1. 手动删除ASP.NET存储在缓存中的CachedVary,假设密钥为"a2" + query"。这似乎有效,但我不确定可靠性。

  2. 添加包含必须从缓存中逐出的页面数组的缓存键,然后删除密钥o使用外部缓存密钥依赖项功能(如果有)。这应该足以模仿我们使用的密钥依赖,但是以更复杂的方式。

  3. 忘掉这一点,放一个短暂的缓存期,让它们过期而不用担心。

  4. 执行我们自己的页面缓存并忘记ASP.NET输出缓存,不太吸引人。

  5. 我确信还有其他方法。任何提示,经验或建议?

1 个答案:

答案 0 :(得分:1)

我用我们为记录采用的解决方案回答了我自己的问题。

在我们的OutputCacheAttribute中,我们添加一个空的缓存对象,其中的键取决于请求的URL和一些参数。这将用于在外部使页面无效。

然后,我们还添加了另一个对象,该对象具有一个取决于当前请求的键,并包含以前的cacheKey。

最后,设置静态ValidationCallback。回调获取当前请求的密钥值,即依赖关键字。然后,如果它不为null,则获取依赖项的值,如果它为null,则依赖关系已被驱逐,我们将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;
    }
}