diff --git a/src/DotNetToolkit.Repository.Caching.InMemory/InMemoryCache.cs b/src/DotNetToolkit.Repository.Caching.InMemory/InMemoryCache.cs deleted file mode 100644 index e598921a..00000000 --- a/src/DotNetToolkit.Repository.Caching.InMemory/InMemoryCache.cs +++ /dev/null @@ -1,136 +0,0 @@ -namespace DotNetToolkit.Repository.Caching.InMemory -{ - using Configuration.Caching; - using JetBrains.Annotations; - using Microsoft.Extensions.Caching.Memory; - using System; - using Utility; - - /// - /// An implementation of . - /// - public class InMemoryCache : ICache - { - #region Fields - - private readonly IMemoryCache _cache; - - #endregion - - #region Constructors - - /// - /// Initializes a new instance of the class. - /// - /// The underlying caching storage. - public InMemoryCache([NotNull] IMemoryCache cache) - { - _cache = Guard.NotNull(cache, nameof(cache)); - } - - #endregion - - #region Private Methods - - private void Set(string key, T value, CacheItemPriority priority, TimeSpan? expiry, Action cacheRemovedCallback = null) - { - Guard.NotEmpty(key, nameof(key)); - - var policy = new MemoryCacheEntryOptions(); - - if (cacheRemovedCallback != null) - { - policy.PostEvictionCallbacks.Add(new PostEvictionCallbackRegistration - { - EvictionCallback = (o, val, reason, state) => - { - cacheRemovedCallback(reason.ToString()); - } - }); - } - - if (expiry.HasValue && expiry.Value != TimeSpan.Zero) - policy.AbsoluteExpiration = DateTimeOffset.Now.Add(expiry.Value); - - if (expiry.HasValue && expiry.Value == TimeSpan.Zero && priority != CacheItemPriority.NeverRemove) - policy.Priority = CacheItemPriority.NeverRemove; - else - policy.Priority = priority; - - _cache.Set(key, value, policy); - } - - #endregion - - #region Implementation of ICache - - /// - /// Create or overwrite an entry in the cache. - /// - /// The type of the cache value. - /// An object identifying the entry. - /// The value to cache. - /// The cache expiration time. - /// A callback function for a value is removed from the cache. - public void Set([NotNull] string key, T value, TimeSpan? expiry, Action cacheRemovedCallback = null) - { - Set(key, value, CacheItemPriority.Normal, expiry, cacheRemovedCallback); - } - - /// - /// Removes the object associated with the given key. - /// - /// An object identifying the entry. - public void Remove([NotNull] string key) - { - _cache.Remove(Guard.NotEmpty(key, nameof(key))); - } - - /// - /// Gets the item associated with this key if present. - /// - /// The type of the cache value. - /// An object identifying the requested entry. - /// The object found in the cache. - /// ctrue if the an object was found with the specified key; otherwise, false. - public bool TryGetValue([NotNull] string key, out T value) - { - return _cache.TryGetValue(Guard.NotEmpty(key, nameof(key)), out value); - } - - /// - /// Increments the number stored at key by one - /// - /// The key. - /// The default value. - /// The increment value. - /// The value of key after the increment. - public int Increment([NotNull] string key, int defaultValue, int incrementValue) - { - Guard.NotEmpty(key, nameof(key)); - - if (!TryGetValue(key, out var current)) - current = defaultValue; - - var value = current + incrementValue; - - Set(key, value, CacheItemPriority.NeverRemove, expiry: null); - - return value; - } - - #endregion - - #region Implementation of IDisposable - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - _cache.Dispose(); - } - - #endregion - } -} diff --git a/src/DotNetToolkit.Repository.Caching.InMemory/InMemoryCacheOptions.cs b/src/DotNetToolkit.Repository.Caching.InMemory/InMemoryCacheOptions.cs new file mode 100644 index 00000000..ebbb260c --- /dev/null +++ b/src/DotNetToolkit.Repository.Caching.InMemory/InMemoryCacheOptions.cs @@ -0,0 +1,52 @@ +namespace DotNetToolkit.Repository.Caching.InMemory +{ + using DotNetToolkit.Repository.Utility; + using JetBrains.Annotations; + using Microsoft.Extensions.Internal; + using System; + + /// + /// The options to be used by the in-memory caching provider. + /// + public class InMemoryCacheOptions + { + internal ISystemClock Clock { get; set; } + internal TimeSpan? ExpirationScanFrequency { get; set; } + internal TimeSpan? Expiry { get; set; } + + internal InMemoryCacheOptions() { } + + /// + /// Adds the giving system clock vaue to the options. + /// + /// The system clock to be added. + public InMemoryCacheOptions WithClock([NotNull] ISystemClock clock) + { + Clock = Guard.NotNull(clock, nameof(clock)); + + return this; + } + + /// + /// Adds the giving system clock vaue to the options. + /// + /// The minimum length of time between successive scans for expired items to be added. + public InMemoryCacheOptions WithExpirationScanFrequency([NotNull] TimeSpan expirationScanFrequency) + { + ExpirationScanFrequency = Guard.NotNull(expirationScanFrequency, nameof(expirationScanFrequency)); + + return this; + } + + /// + /// Adds the giving caching expiration time to the options. + /// + /// The caching expiration time to be added. + public InMemoryCacheOptions WithExpiry([NotNull] TimeSpan expiry) + { + Expiry = Guard.NotNull(expiry, nameof(expiry)); + + return this; + } + } +} diff --git a/src/DotNetToolkit.Repository.Caching.InMemory/InMemoryCacheProvider.cs b/src/DotNetToolkit.Repository.Caching.InMemory/InMemoryCacheProvider.cs index 022154e4..40d200c0 100644 --- a/src/DotNetToolkit.Repository.Caching.InMemory/InMemoryCacheProvider.cs +++ b/src/DotNetToolkit.Repository.Caching.InMemory/InMemoryCacheProvider.cs @@ -3,54 +3,29 @@ using Configuration.Caching; using JetBrains.Annotations; using Microsoft.Extensions.Caching.Memory; + using Microsoft.Extensions.Internal; using System; using Utility; - /// - /// An implementation of . - /// - public class InMemoryCacheProvider : CacheProviderBase + internal class InMemoryCacheProvider : ICacheProvider { + #region Properties + + public IMemoryCache Cache { get; } + public TimeSpan? Expiry { get; set; } + + #endregion + #region Constructors - /// - /// Initializes a new instance of the class. - /// - public InMemoryCacheProvider() : this((TimeSpan?)null) { } - - /// - /// Initializes a new instance of the class. - /// - /// The caching expiration time. - public InMemoryCacheProvider([CanBeNull] TimeSpan? expiry) : this(new MemoryCache(new MemoryCacheOptions()), expiry) { } - - /// - /// Initializes a new instance of the class. - /// - /// The configuration options action. - public InMemoryCacheProvider([NotNull] Action optionsAction) : this(optionsAction, (TimeSpan?)null) { } - - /// - /// Initializes a new instance of the class. - /// - /// The configuration options action. - /// The caching expiration time. - public InMemoryCacheProvider([NotNull] Action optionsAction, [CanBeNull] TimeSpan? expiry) : this(new MemoryCache(GetConfigurationOptions(optionsAction)), expiry) { } - - /// - /// Initializes a new instance of the class. - /// - /// The underlying caching storage. - public InMemoryCacheProvider([NotNull] IMemoryCache cache) : this(cache, (TimeSpan?)null) { } - - /// - /// Initializes a new instance of the class. - /// - /// The underlying caching storage. - /// The caching expiration time. - public InMemoryCacheProvider([NotNull] IMemoryCache cache, [CanBeNull] TimeSpan? expiry) + public InMemoryCacheProvider() : this(null, null, null) { } + + public InMemoryCacheProvider(ISystemClock clock, TimeSpan? expirationScanFrequency, TimeSpan? expiry) + : this (GetMemoryCacheOptions(clock, expirationScanFrequency), expiry) { } + + private InMemoryCacheProvider(MemoryCacheOptions options, TimeSpan? expiry) { - Cache = new InMemoryCache(Guard.NotNull(cache, nameof(cache))); + Cache = new MemoryCache(Guard.NotNull(options, nameof(options))); Expiry = expiry; } @@ -58,17 +33,81 @@ public InMemoryCacheProvider([NotNull] IMemoryCache cache, [CanBeNull] TimeSpan? #region Private Methods - private static MemoryCacheOptions GetConfigurationOptions(Action optionsAction) + private static MemoryCacheOptions GetMemoryCacheOptions(ISystemClock clock, TimeSpan? expirationScanFrequency) { - Guard.NotNull(optionsAction, nameof(optionsAction)); - var options = new MemoryCacheOptions(); - optionsAction(options); + options.Clock = clock; + + if (expirationScanFrequency.HasValue) + { + options.ExpirationScanFrequency = expirationScanFrequency.Value; + } return options; } + private void Set(string key, T value, CacheItemPriority priority, TimeSpan? expiry, Action cacheRemovedCallback = null) + { + Guard.NotEmpty(key, nameof(key)); + + var policy = new MemoryCacheEntryOptions(); + + if (cacheRemovedCallback != null) + { + policy.PostEvictionCallbacks.Add(new PostEvictionCallbackRegistration + { + EvictionCallback = (o, val, reason, state) => + { + cacheRemovedCallback(reason.ToString()); + } + }); + } + + if (expiry.HasValue && expiry.Value != TimeSpan.Zero) + policy.AbsoluteExpiration = DateTimeOffset.Now.Add(expiry.Value); + + if (expiry.HasValue && expiry.Value == TimeSpan.Zero && priority != CacheItemPriority.NeverRemove) + policy.Priority = CacheItemPriority.NeverRemove; + else + policy.Priority = priority; + + Cache.Set(key, value, policy); + } + + #endregion + + #region Implementation of ICacheProvider + + public void Set([NotNull] string key, T value, TimeSpan? expiry = null, Action cacheRemovedCallback = null) + { + Set(key, value, CacheItemPriority.Normal, expiry ?? Expiry, cacheRemovedCallback); + } + + public void Remove([NotNull] string key) + { + Cache.Remove(Guard.NotEmpty(key, nameof(key))); + } + + public bool TryGetValue([NotNull] string key, out T value) + { + return Cache.TryGetValue(Guard.NotEmpty(key, nameof(key)), out value); + } + + public int Increment([NotNull] string key, int defaultValue, int incrementValue) + { + Guard.NotEmpty(key, nameof(key)); + + if (!TryGetValue(key, out var current)) + current = defaultValue; + + var value = current + incrementValue; + + Set(key, value, CacheItemPriority.NeverRemove, expiry: null); + + return value; + } + #endregion } }