我们正在重构我们的网站以使用外部缓存,我们采取的第一步是使用自定义OutputCacheProvider
。首先,我们创建了一个简单的提供程序,它只包含MemoryCache
,并发现我们管理依赖项的方式存在问题。
我们有一个自定义OutputCacheAttribute
,它添加了一个额外的密钥依赖项,以便在某些实体更改时能够使一组页面无效,并保留此功能,我看到了一些选项:
手动删除ASP.NET存储在缓存中的CachedVary
,假设密钥为"a2" + query"
。这似乎有效,但我不确定可靠性。
添加包含必须从缓存中逐出的页面数组的缓存键,然后删除密钥o使用外部缓存密钥依赖项功能(如果有)。这应该足以模仿我们使用的密钥依赖,但是以更复杂的方式。
忘掉这一点,放一个短暂的缓存期,让它们过期而不用担心。
执行我们自己的页面缓存并忘记ASP.NET输出缓存,不太吸引人。
我确信还有其他方法。任何提示,经验或建议?
答案 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;
}
}