2014-04-17 40 views
0

我的項目主要使用.net MemoryCache,但我確實有一個使用HTTPCache的組件。這使得交叉依賴更難以處理。HTTPCache和MemoryCache交叉依賴

是否有無論如何我可以讓兩個緩存相互依賴?例如一個HTTPCacheChangeMonitor我可以給MemoryCache和一個MemoryCacheDependency,我可以給HTTPCache。

回答

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); 
    } 
}