diff --git a/LazyCache.AspNetCore/LazyCacheServiceCollectionExtensions.cs b/LazyCache.AspNetCore/LazyCacheServiceCollectionExtensions.cs index eb242ff..2129fb9 100644 --- a/LazyCache.AspNetCore/LazyCacheServiceCollectionExtensions.cs +++ b/LazyCache.AspNetCore/LazyCacheServiceCollectionExtensions.cs @@ -3,6 +3,7 @@ using LazyCache.Providers; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; // ReSharper disable once CheckNamespace - MS guidelines say put DI registration in this NS namespace Microsoft.Extensions.DependencyInjection @@ -15,8 +16,8 @@ public static IServiceCollection AddLazyCache(this IServiceCollection services) if (services == null) throw new ArgumentNullException(nameof(services)); services.AddOptions(); - services.TryAdd(ServiceDescriptor.Singleton()); - services.TryAdd(ServiceDescriptor.Singleton()); + services.TryAdd(ServiceDescriptor.Singleton(serviceProvider => + new MemoryCacheProvider(() => new MemoryCache(new MemoryCacheOptions())))); services.TryAdd(ServiceDescriptor.Singleton()); @@ -30,8 +31,8 @@ public static IServiceCollection AddLazyCache(this IServiceCollection services, if (implementationFactory == null) throw new ArgumentNullException(nameof(implementationFactory)); services.AddOptions(); - services.TryAdd(ServiceDescriptor.Singleton()); - services.TryAdd(ServiceDescriptor.Singleton()); + services.TryAdd(ServiceDescriptor.Singleton(serviceProvider => + new MemoryCacheProvider(() => new MemoryCache(new MemoryCacheOptions())))); services.TryAdd(ServiceDescriptor.Singleton(implementationFactory)); diff --git a/LazyCache.Ninject/LazyCacheModule.cs b/LazyCache.Ninject/LazyCacheModule.cs index c1d7531..d753cd9 100644 --- a/LazyCache.Ninject/LazyCacheModule.cs +++ b/LazyCache.Ninject/LazyCacheModule.cs @@ -2,6 +2,7 @@ using LazyCache.Providers; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; +using Ninject; using Ninject.Modules; namespace LazyCache @@ -23,8 +24,8 @@ public LazyCacheModule(Func implementationFactory) public override void Load() { Bind>().ToConstant(Options.Create(new MemoryCacheOptions())); - Bind().To().InSingletonScope(); - Bind().To().InSingletonScope(); + Bind().To().InSingletonScope() + .WithConstructorArgument>(context => () => new MemoryCache(context.Kernel.Get>())); if (implementationFactory == null) Bind().To().InSingletonScope(); diff --git a/LazyCache.UnitTests/CachingServiceMemoryCacheProviderTests.cs b/LazyCache.UnitTests/CachingServiceMemoryCacheProviderTests.cs index 85e5e8b..d3e724f 100644 --- a/LazyCache.UnitTests/CachingServiceMemoryCacheProviderTests.cs +++ b/LazyCache.UnitTests/CachingServiceMemoryCacheProviderTests.cs @@ -21,7 +21,7 @@ public void BeforeEachTest() private static CachingService BuildCache() { - return new CachingService(new MemoryCacheProvider(new MemoryCache(new MemoryCacheOptions()))); + return new CachingService(new MemoryCacheProvider(() => new MemoryCache(new MemoryCacheOptions()))); } private IAppCache sut; @@ -755,5 +755,18 @@ public void RemovedItemCannotBeRetrievedFromCache() sut.Remove(TestKey); Assert.Null(sut.Get(TestKey)); } + + [Test] + public void NoItemsCanBeRetrievedFromCacheAfterRemoveAll() + { + var testKey2 = "TestKey2"; + sut.Add(TestKey, new object()); + sut.Add(testKey2, new object()); + Assert.NotNull(sut.Get(TestKey)); + Assert.NotNull(sut.Get(testKey2)); + sut.RemoveAll(); + Assert.Null(sut.Get(TestKey)); + Assert.Null(sut.Get(testKey2)); + } } } \ No newline at end of file diff --git a/LazyCache/CachingService.cs b/LazyCache/CachingService.cs index 1bd5305..824fcff 100644 --- a/LazyCache/CachingService.cs +++ b/LazyCache/CachingService.cs @@ -36,7 +36,7 @@ public CachingService(ICacheProvider cache) : this(() => cache) public static Lazy DefaultCacheProvider { get; set; } = new Lazy(() => - new MemoryCacheProvider( + new MemoryCacheProvider(() => new MemoryCache( new MemoryCacheOptions()) )); @@ -122,6 +122,11 @@ public virtual void Remove(string key) CacheProvider.Remove(key); } + public virtual void RemoveAll() + { + CacheProvider.RemoveAll(); + } + public virtual ICacheProvider CacheProvider => cacheProvider.Value; public virtual async Task GetOrAddAsync(string key, Func> addItemFactory) diff --git a/LazyCache/IAppCache.cs b/LazyCache/IAppCache.cs index b474cbe..e133f6b 100644 --- a/LazyCache/IAppCache.cs +++ b/LazyCache/IAppCache.cs @@ -24,5 +24,7 @@ public interface IAppCache Task GetOrAddAsync(string key, Func> addItemFactory); void Remove(string key); + + void RemoveAll(); } } \ No newline at end of file diff --git a/LazyCache/ICacheProvider.cs b/LazyCache/ICacheProvider.cs index 2007416..b065c0e 100644 --- a/LazyCache/ICacheProvider.cs +++ b/LazyCache/ICacheProvider.cs @@ -10,6 +10,7 @@ public interface ICacheProvider : IDisposable object Get(string key); object GetOrCreate(string key, Func func); void Remove(string key); + void RemoveAll(); Task GetOrCreateAsync(string key, Func> func); } } \ No newline at end of file diff --git a/LazyCache/Mocks/MockCacheProvider.cs b/LazyCache/Mocks/MockCacheProvider.cs index c7463e7..4ee3ed4 100644 --- a/LazyCache/Mocks/MockCacheProvider.cs +++ b/LazyCache/Mocks/MockCacheProvider.cs @@ -24,6 +24,10 @@ public void Remove(string key) { } + public void RemoveAll() + { + } + public Task GetOrCreateAsync(string key, Func> func) { return func(null); diff --git a/LazyCache/Mocks/MockCachingService.cs b/LazyCache/Mocks/MockCachingService.cs index 51b92fd..a10857f 100644 --- a/LazyCache/Mocks/MockCachingService.cs +++ b/LazyCache/Mocks/MockCachingService.cs @@ -27,6 +27,10 @@ public void Remove(string key) { } + public void RemoveAll() + { + } + public Task GetOrAddAsync(string key, Func> addItemFactory) { return addItemFactory(new MockCacheEntry(key)); diff --git a/LazyCache/Providers/MemoryCacheProvider.cs b/LazyCache/Providers/MemoryCacheProvider.cs index 9bdfdc9..6c65f71 100644 --- a/LazyCache/Providers/MemoryCacheProvider.cs +++ b/LazyCache/Providers/MemoryCacheProvider.cs @@ -6,11 +6,13 @@ namespace LazyCache.Providers { public class MemoryCacheProvider : ICacheProvider { - internal readonly IMemoryCache cache; + internal readonly Func cacheFactory; + internal IMemoryCache cache; - public MemoryCacheProvider(IMemoryCache cache) + public MemoryCacheProvider(Func cacheFactory) { - this.cache = cache; + this.cacheFactory = cacheFactory; + cache = cacheFactory(); } public void Set(string key, object item, MemoryCacheEntryOptions policy) @@ -33,6 +35,12 @@ public void Remove(string key) cache.Remove(key); } + public void RemoveAll() + { + var oldCache = System.Threading.Interlocked.Exchange(ref cache, cacheFactory()); + oldCache?.Dispose(); + } + public Task GetOrCreateAsync(string key, Func> factory) { return cache.GetOrCreateAsync(key, factory);