我的项目主要是使用.net MemoryCache,但我确实有一个使用HTTPCache的组件。这使得交叉依赖更难以处理。
无论如何,我可以让两个缓存相互依赖吗?例如,我可以提供给MemoryCache的HTTPCacheChangeMonitor和一个可以提供给HTTPCache的MemoryCacheDependency。
答案 0 :(得分:0)
自发布此问题以来,我一直致力于实现一些跨缓存依赖项。不确定他们是否采取了最好的方法。
<强> HttpCacheChangeMonitor 强>
允许ObjectCache项依赖于HTTPCache
public class HttpCacheChangeMonitor : ChangeMonitor
{
private readonly string _uniqueId = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
private readonly string[] _httpCacheKeys;
public override string UniqueId
{
get { return _uniqueId; }
}
public HttpCacheChangeMonitor(string httpCacheKey)
: this(new[] { httpCacheKey }) { }
public HttpCacheChangeMonitor(string[] httpCacheKeys)
{
_httpCacheKeys = httpCacheKeys;
Initialise();
}
private void Initialise()
{
HttpRuntime.Cache.Add(_uniqueId, _uniqueId, new CacheDependency(null, _httpCacheKeys), DateTime.MaxValue, Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, Callback);
InitializationComplete();
}
private void Callback(string key, object value, CacheItemRemovedReason reason)
{
OnChanged(null);
}
protected override void Dispose(bool disposing)
{
Debug.WriteLine(
_uniqueId + " notifying cache of change.", "HttpCacheChangeMonitor");
HttpRuntime.Cache.Remove(_uniqueId);
}
}
<强>测试强>
public class HttpCacheChangeMonitorTests
{
[Fact]
public void ChangeMonitorTest()
{
HttpRuntime.Cache.Add("ChangeMonitorTest1", "", null, Cache.NoAbsoluteExpiration, new TimeSpan(0,10,0), CacheItemPriority.Normal, null);
HttpRuntime.Cache.Add("ChangeMonitorTest2", "", null, Cache.NoAbsoluteExpiration, new TimeSpan(0, 10, 0), CacheItemPriority.Normal, null);
using (MemoryCache cache = new MemoryCache("TestCache", new NameValueCollection()))
{
// Add data to cache
for (int idx = 0; idx < 10; idx++)
{
cache.Add("Key" + idx, "Value" + idx, GetPolicy(idx));
}
long middleCount = cache.GetCount();
// Flush cached items associated with "NamedData" change monitors
HttpRuntime.Cache.Remove("ChangeMonitorTest1");
long finalCount = cache.GetCount();
Assert.Equal(10, middleCount);
Assert.Equal(5, middleCount - finalCount);
HttpRuntime.Cache.Remove("ChangeMonitorTest2");
}
}
private static CacheItemPolicy GetPolicy(int idx)
{
string name = (idx % 2 == 0) ? "ChangeMonitorTest1" : "ChangeMonitorTest2";
CacheItemPolicy cip = new CacheItemPolicy();
cip.AbsoluteExpiration = System.DateTimeOffset.UtcNow.AddHours(1);
cip.ChangeMonitors.Add(new HttpCacheChangeMonitor(name));
return cip;
}
}
<强> MemoryCacheDependency 强>
允许HttpCache项依赖于MemoryCache
public class MemoryCacheDependency : CacheDependency
{
private readonly string _uniqueId = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
private readonly IEnumerable<string> _cacheKeys;
private readonly MemoryCache _cache;
public override string GetUniqueID()
{
return _uniqueId;
}
public MemoryCacheDependency(MemoryCache cache, string cacheKey)
: this(cache, new[] { cacheKey }) { }
public MemoryCacheDependency(MemoryCache cache, IEnumerable<string> cacheKeys)
{
_cache = cache;
_cacheKeys = cacheKeys;
Initialise();
}
private void Initialise()
{
var monitor = _cache.CreateCacheEntryChangeMonitor(_cacheKeys);
CacheItemPolicy pol = new CacheItemPolicy{AbsoluteExpiration = DateTime.MaxValue, Priority = CacheItemPriority.NotRemovable};
pol.ChangeMonitors.Add(monitor);
pol.RemovedCallback = Callback;
_cache.Add(_uniqueId, _uniqueId, pol);
FinishInit();
}
private void Callback(CacheEntryRemovedArguments arguments)
{
NotifyDependencyChanged(arguments.Source, EventArgs.Empty);
}
protected override void DependencyDispose()
{
Debug.WriteLine(
_uniqueId + " notifying cache of change.", "ObjectCacheDependency");
_cache.Remove(_uniqueId);
base.DependencyDispose();
}
}
<强>测试强>
public class MemoryCacheDependencyTests
{
[Fact]
public void CacheDependencyTest()
{
using (MemoryCache cache = new MemoryCache("TestCache", new NameValueCollection()))
{
cache.Add("HttpCacheTest1", DateTime.Now, new CacheItemPolicy {SlidingExpiration = new TimeSpan(0, 10, 0)});
cache.Add("HttpCacheTest2", DateTime.Now, new CacheItemPolicy {SlidingExpiration = new TimeSpan(0, 10, 0)});
// Add data to cache
for (int idx = 0; idx < 10; idx++)
{
HttpRuntime.Cache.Add("Key" + idx, "Value" + idx, GetDependency(cache, idx), Cache.NoAbsoluteExpiration, new TimeSpan(0,10,0), CacheItemPriority.NotRemovable, null);
}
int middleCount = HttpRuntime.Cache.Count;
// Flush cached items associated with "NamedData" change monitors
cache.Remove("HttpCacheTest1");
int finalCount = HttpRuntime.Cache.Count;
Assert.Equal(10, middleCount);
Assert.Equal(5, middleCount - finalCount);
}
}
private static CacheDependency GetDependency(MemoryCache cache, int idx)
{
string name = (idx % 2 == 0) ? "HttpCacheTest1" : "HttpCacheTest2";
return new MemoryCacheDependency(cache, name);
}
}