diff --git a/src/Umbraco.Core/Persistence/Caching/RuntimeCacheProvider.cs b/src/Umbraco.Core/Persistence/Caching/RuntimeCacheProvider.cs index 06a624a771..60e176096f 100644 --- a/src/Umbraco.Core/Persistence/Caching/RuntimeCacheProvider.cs +++ b/src/Umbraco.Core/Persistence/Caching/RuntimeCacheProvider.cs @@ -59,23 +59,41 @@ namespace Umbraco.Core.Persistence.Caching var item = _memoryCache != null ? _memoryCache.Get(key) : HttpRuntime.Cache.Get(key); - return item as IEntity; + var result = item as IEntity; + if (result == null) + { + //ensure the key doesn't exist anymore in the tracker + _keyTracker.Remove(key); + } + return result; } public IEnumerable GetByIds(Type type, List ids) { + var collection = new List(); foreach (var guid in ids) { + var key = GetCompositeId(type, guid); var item = _memoryCache != null - ? _memoryCache.Get(GetCompositeId(type, guid)) - : HttpRuntime.Cache.Get(GetCompositeId(type, guid)); - - yield return item as IEntity; + ? _memoryCache.Get(key) + : HttpRuntime.Cache.Get(key); + var result = item as IEntity; + if (result == null) + { + //ensure the key doesn't exist anymore in the tracker + _keyTracker.Remove(key); + } + else + { + collection.Add(result); + } } + return collection; } public IEnumerable GetAllByType(Type type) { + var collection = new List(); foreach (var key in _keyTracker) { if (key.StartsWith(string.Format("{0}{1}-", CacheItemPrefix, type.Name))) @@ -84,9 +102,19 @@ namespace Umbraco.Core.Persistence.Caching ? _memoryCache.Get(key) : HttpRuntime.Cache.Get(key); - yield return item as IEntity; + var result = item as IEntity; + if (result == null) + { + //ensure the key doesn't exist anymore in the tracker + _keyTracker.Remove(key); + } + else + { + collection.Add(result); + } } } + return collection; } public void Save(Type type, IEntity entity) @@ -159,21 +187,27 @@ namespace Umbraco.Core.Persistence.Caching { _keyTracker.Clear(); - if (_memoryCache != null) + ClearDataCache(); + } + } + + //DO not call this unless it's for testing since it clears the data cached but not the keys + internal void ClearDataCache() + { + if (_memoryCache != null) + { + _memoryCache.DisposeIfDisposable(); + _memoryCache = new MemoryCache("in-memory"); + } + else + { + foreach (DictionaryEntry c in HttpRuntime.Cache) { - _memoryCache.DisposeIfDisposable(); - _memoryCache = new MemoryCache("in-memory"); - } - else - { - foreach (DictionaryEntry c in HttpRuntime.Cache) + if (c.Key is string && ((string)c.Key).InvariantStartsWith(CacheItemPrefix)) { - if (c.Key is string && ((string)c.Key).InvariantStartsWith(CacheItemPrefix)) - { - if (HttpRuntime.Cache[(string)c.Key] == null) return; - HttpRuntime.Cache.Remove((string)c.Key); - } - } + if (HttpRuntime.Cache[(string)c.Key] == null) return; + HttpRuntime.Cache.Remove((string)c.Key); + } } } } diff --git a/src/Umbraco.Tests/Persistence/Caching/RuntimeCacheProviderTest.cs b/src/Umbraco.Tests/Persistence/Caching/RuntimeCacheProviderTest.cs index 8c176df515..bbf4bc381a 100644 --- a/src/Umbraco.Tests/Persistence/Caching/RuntimeCacheProviderTest.cs +++ b/src/Umbraco.Tests/Persistence/Caching/RuntimeCacheProviderTest.cs @@ -34,6 +34,26 @@ namespace Umbraco.Tests.Persistence.Caching _registry.Save(typeof(MockedEntity), entity6); } + [Test] + public void Tracked_Keys_Removed_When_Cache_Removed() + { + _registry = RuntimeCacheProvider.Current; + + //Fill the registry with random entities + var entity1 = new MockedEntity { Id = 1, Key = 1.ToGuid(), Alias = "mocked1", Name = "Mocked1", Value = Guid.NewGuid().ToString("n") }; + var entity2 = new MockedEntity { Id = 2, Key = 2.ToGuid(), Alias = "mocked2", Name = "Mocked2", Value = Guid.NewGuid().ToString("n") }; + var entity3 = new MockedEntity { Id = 3, Key = 3.ToGuid(), Alias = "mocked3", Name = "Mocked3", Value = Guid.NewGuid().ToString("n") }; + + _registry.Save(typeof(MockedEntity), entity1); + _registry.Save(typeof(MockedEntity), entity2); + _registry.Save(typeof(MockedEntity), entity3); + + //now clear the runtime cache internally + ((RuntimeCacheProvider)_registry).ClearDataCache(); + + Assert.AreEqual(0, _registry.GetAllByType(typeof (MockedEntity)).Count()); + } + [Test] public void Can_Clear_By_Type() {