From ce3a186cc02f977b571bfc1d5bff508b46ceb39e Mon Sep 17 00:00:00 2001
From: ali zaferany <ali.zaferany79@gmail.com>
Date: Sun, 11 Sep 2022 12:33:50 +0430
Subject: [PATCH] add LazyCacheOptions and use Options Pattern

---
 .../LazyCacheServiceCollectionExtensions.cs      | 12 +++++++++---
 LazyCache.UnitTests/AspNetCoreTests.cs           | 16 ++++++++++++++++
 LazyCache/CachingService.cs                      | 14 ++++++++++++++
 LazyCache/LazyCacheOptions.cs                    | 11 +++++++++++
 4 files changed, 50 insertions(+), 3 deletions(-)
 create mode 100644 LazyCache/LazyCacheOptions.cs

diff --git a/LazyCache.AspNetCore/LazyCacheServiceCollectionExtensions.cs b/LazyCache.AspNetCore/LazyCacheServiceCollectionExtensions.cs
index 4eb7182..e1b99b3 100644
--- a/LazyCache.AspNetCore/LazyCacheServiceCollectionExtensions.cs
+++ b/LazyCache.AspNetCore/LazyCacheServiceCollectionExtensions.cs
@@ -10,6 +10,13 @@ namespace Microsoft.Extensions.DependencyInjection
     // See https://github.com/dotnet/runtime/blob/master/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCacheServiceCollectionExtensions.cs
     public static class LazyCacheServiceCollectionExtensions
     {
+        public static IServiceCollection AddLazyCache(this IServiceCollection services, Action<LazyCacheOptions> setupAction)
+        {
+            services.AddLazyCache();
+            services.Configure(setupAction);
+            return services;
+        }
+
         public static IServiceCollection AddLazyCache(this IServiceCollection services)
         {
             if (services == null) throw new ArgumentNullException(nameof(services));
@@ -18,13 +25,12 @@ public static IServiceCollection AddLazyCache(this IServiceCollection services)
             services.TryAdd(ServiceDescriptor.Singleton<IMemoryCache, MemoryCache>());
             services.TryAdd(ServiceDescriptor.Singleton<ICacheProvider, MemoryCacheProvider>());
 
-            services.TryAdd(ServiceDescriptor.Singleton<IAppCache, CachingService>(serviceProvider => 
-                new CachingService(
-                    new Lazy<ICacheProvider>(serviceProvider.GetRequiredService<ICacheProvider>))));
+            services.TryAdd(ServiceDescriptor.Singleton<IAppCache, CachingService>());
 
             return services;
         }
 
+        [Obsolete("use other signature for change options")]
         public static IServiceCollection AddLazyCache(this IServiceCollection services,
             Func<IServiceProvider, CachingService> implementationFactory)
         {
diff --git a/LazyCache.UnitTests/AspNetCoreTests.cs b/LazyCache.UnitTests/AspNetCoreTests.cs
index deabd8c..1a2a38d 100644
--- a/LazyCache.UnitTests/AspNetCoreTests.cs
+++ b/LazyCache.UnitTests/AspNetCoreTests.cs
@@ -38,5 +38,21 @@ public void CanResolveCacheFromServiceCollectionAsService()
             cache.Should().NotBeNull();
             result.Should().NotBeNull();
         }
+        
+        [Test]
+        public void CanResolveCacheFromServiceCollectionWithOptionsAsService()
+        {
+            var container = new ServiceCollection();
+            var cacheDurationSeconds = 12345;
+            container.AddLazyCache(options => options.DefaultCacheDurationSeconds = cacheDurationSeconds);
+            var provider = container.BuildServiceProvider();
+
+            var cache = provider.GetService<IAppCache>();
+            var result = cache?.GetOrAdd("key", () => new object());
+
+            cache.Should().NotBeNull();
+            cache.DefaultCachePolicy.DefaultCacheDurationSeconds.Should().Be(cacheDurationSeconds);
+            result.Should().NotBeNull();
+        }
     }
 }
diff --git a/LazyCache/CachingService.cs b/LazyCache/CachingService.cs
index df091de..c8a31aa 100644
--- a/LazyCache/CachingService.cs
+++ b/LazyCache/CachingService.cs
@@ -4,6 +4,8 @@
 using System.Threading.Tasks;
 using LazyCache.Providers;
 using Microsoft.Extensions.Caching.Memory;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
 
 namespace LazyCache
 {
@@ -13,6 +15,7 @@ public class CachingService : IAppCache
         private readonly Lazy<ICacheProvider> cacheProvider;
 
         private readonly int[] keyLocks;
+        private readonly LazyCacheOptions _options;
 
         public CachingService() : this(DefaultCacheProvider)
         {
@@ -34,6 +37,17 @@ public CachingService(Func<ICacheProvider> cacheProviderFactory)
 
         }
 
+        [ActivatorUtilitiesConstructor]
+        public CachingService(ICacheProvider cacheProvider, IOptions<LazyCacheOptions> options)
+        {
+            if (cacheProvider == null) throw new ArgumentNullException(nameof(cacheProvider));
+            _options = options.Value;
+            this.cacheProvider = new Lazy<ICacheProvider>(() => cacheProvider);
+            keyLocks = new int[_options.NumberOfKeyLocks];
+            DefaultCachePolicy.DefaultCacheDurationSeconds = _options.DefaultCacheDurationSeconds;
+
+        }
+        
         public CachingService(ICacheProvider cache) : this(() => cache)
         {
             if (cache == null) throw new ArgumentNullException(nameof(cache));
diff --git a/LazyCache/LazyCacheOptions.cs b/LazyCache/LazyCacheOptions.cs
new file mode 100644
index 0000000..bb08cf7
--- /dev/null
+++ b/LazyCache/LazyCacheOptions.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace LazyCache
+{
+    public class LazyCacheOptions
+    {
+        public int DefaultCacheDurationSeconds { get; set; } = 60 * 20;
+        public int NumberOfKeyLocks { get; set; } = Math.Max(Environment.ProcessorCount * 8, 32);
+
+    }
+}
\ No newline at end of file