From a9ffe66032cd9c3d5a24c06c47b9fdd3d59e01ca Mon Sep 17 00:00:00 2001 From: Galip Tolga Erdem Date: Mon, 14 Oct 2019 22:44:22 +0300 Subject: [PATCH 1/3] closes #1900 Implementation of IDistributedCache --- .../Volo/Abp/Caching/AbpCachingModule.cs | 1 + .../Volo/Abp/Caching/DistributedCache.cs | 323 ++++++++++++++++++ .../Volo/Abp/Caching/IDistributedCache.cs | 144 ++++++++ .../Abp/Caching/DistributedCache_Tests.cs | 145 ++++++++ .../Volo/Abp/Caching/PersonCacheItem.cs | 7 + 5 files changed, 620 insertions(+) diff --git a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/AbpCachingModule.cs b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/AbpCachingModule.cs index 48d55cc0d5..0502cd8d81 100644 --- a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/AbpCachingModule.cs +++ b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/AbpCachingModule.cs @@ -21,6 +21,7 @@ namespace Volo.Abp.Caching context.Services.AddDistributedMemoryCache(); context.Services.AddSingleton(typeof(IDistributedCache<>), typeof(DistributedCache<>)); + context.Services.AddSingleton(typeof(IDistributedCache<,>), typeof(DistributedCache<,>)); context.Services.Configure(cacheOptions => { diff --git a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs index caa51aeac1..654e60f323 100644 --- a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs +++ b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs @@ -439,4 +439,327 @@ namespace Volo.Abp.Caching DefaultCacheOptions = GetDefaultCacheEntryOptions(); } } + /// + /// Represents a distributed cache of type. + /// Uses a generic cache key type of type. + /// + /// The type of cache item being cached. + /// The type of cache key being used. + public class DistributedCache : IDistributedCache + where TCacheItem : class + { + public ILogger> Logger { get; set; } + + protected string CacheName { get; set; } + + protected bool IgnoreMultiTenancy { get; set; } + + protected IDistributedCache Cache { get; } + + protected ICancellationTokenProvider CancellationTokenProvider { get; } + + protected IDistributedCacheSerializer Serializer { get; } + + protected ICurrentTenant CurrentTenant { get; } + + protected SemaphoreSlim SyncSemaphore { get; } + + protected DistributedCacheEntryOptions DefaultCacheOptions; + + private readonly CacheOptions _cacheOption; + + private readonly DistributedCacheOptions _distributedCacheOption; + + public DistributedCache( + IOptions cacheOption, + IOptions distributedCacheOption, + IDistributedCache cache, + ICancellationTokenProvider cancellationTokenProvider, + IDistributedCacheSerializer serializer, + ICurrentTenant currentTenant) + { + _distributedCacheOption = distributedCacheOption.Value; + _cacheOption = cacheOption.Value; + Cache = cache; + CancellationTokenProvider = cancellationTokenProvider; + Logger = NullLogger>.Instance; + Serializer = serializer; + CurrentTenant = currentTenant; + + SyncSemaphore = new SemaphoreSlim(1, 1); + + SetDefaultOptions(); + } + protected virtual string NormalizeKey(string key) + { + var normalizedKey = "c:" + CacheName + ",k:" + _cacheOption.KeyPrefix + key; + + if (!IgnoreMultiTenancy && CurrentTenant.Id.HasValue) + { + normalizedKey = "t:" + CurrentTenant.Id.Value + "," + normalizedKey; + } + + return normalizedKey; + } + + protected virtual DistributedCacheEntryOptions GetDefaultCacheEntryOptions() + { + foreach (var configure in _cacheOption.CacheConfigurators) + { + var options = configure.Invoke(CacheName); + if (options != null) + { + return options; + } + } + return _cacheOption.GlobalCacheEntryOptions; + } + + protected virtual void SetDefaultOptions() + { + CacheName = CacheNameAttribute.GetCacheName(typeof(TCacheItem)); + + //IgnoreMultiTenancy + IgnoreMultiTenancy = typeof(TCacheItem).IsDefined(typeof(IgnoreMultiTenancyAttribute), true); + + //Configure default cache entry options + DefaultCacheOptions = GetDefaultCacheEntryOptions(); + } + public virtual TCacheItem Get(TCacheKey key, bool? hideErrors = null) + { + hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; + + byte[] cachedBytes; + + try + { + cachedBytes = Cache.Get(NormalizeKey(key?.ToString())); + } + catch (Exception ex) + { + if (hideErrors == true) + { + Logger.LogException(ex, LogLevel.Warning); + return null; + } + + throw; + } + + if (cachedBytes == null) + { + return null; + } + + return Serializer.Deserialize(cachedBytes); + } + + public virtual async Task GetAsync(TCacheKey key, bool? hideErrors = null, CancellationToken token = default) + { + hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; + + byte[] cachedBytes; + + try + { + cachedBytes = await Cache.GetAsync( + NormalizeKey(key.ToString()), + CancellationTokenProvider.FallbackToProvider(token) + ); + } + catch (Exception ex) + { + if (hideErrors == true) + { + Logger.LogException(ex, LogLevel.Warning); + return null; + } + + throw; + } + + if (cachedBytes == null) + { + return null; + } + + return Serializer.Deserialize(cachedBytes); + } + + public virtual TCacheItem GetOrAdd(TCacheKey key, Func factory, Func optionsFactory = null, bool? hideErrors = null) + { + var value = Get(key, hideErrors); + if (value != null) + { + return value; + } + + using (SyncSemaphore.Lock()) + { + value = Get(key, hideErrors); + if (value != null) + { + return value; + } + + value = factory(); + Set(key, value, optionsFactory?.Invoke(), hideErrors); + } + + return value; + } + + public virtual async Task GetOrAddAsync(TCacheKey key, Func> factory, Func optionsFactory = null, bool? hideErrors = null, CancellationToken token = default) + { + token = CancellationTokenProvider.FallbackToProvider(token); + var value = await GetAsync(key, hideErrors, token); + if (value != null) + { + return value; + } + + using (await SyncSemaphore.LockAsync(token)) + { + value = await GetAsync(key, hideErrors, token); + if (value != null) + { + return value; + } + + value = await factory(); + await SetAsync(key, value, optionsFactory?.Invoke(), hideErrors, token); + } + + return value; + } + + public virtual void Set(TCacheKey key, TCacheItem value, DistributedCacheEntryOptions options = null, bool? hideErrors = null) + { + hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; + + try + { + Cache.Set( + NormalizeKey(key.ToString()), + Serializer.Serialize(value), + options ?? DefaultCacheOptions + ); + } + catch (Exception ex) + { + if (hideErrors == true) + { + Logger.LogException(ex, LogLevel.Warning); + return; + } + + throw; + } + } + + public virtual async Task SetAsync(TCacheKey key, TCacheItem value, DistributedCacheEntryOptions options = null, bool? hideErrors = null, CancellationToken token = default) + { + hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; + + try + { + await Cache.SetAsync( + NormalizeKey(key.ToString()), + Serializer.Serialize(value), + options ?? DefaultCacheOptions, + CancellationTokenProvider.FallbackToProvider(token) + ); + } + catch (Exception ex) + { + if (hideErrors == true) + { + Logger.LogException(ex, LogLevel.Warning); + return; + } + + throw; + } + } + + public virtual void Refresh(TCacheKey key, bool? hideErrors = null) + { + hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; + + try + { + Cache.Refresh(NormalizeKey(key.ToString())); + } + catch (Exception ex) + { + if (hideErrors == true) + { + Logger.LogException(ex, LogLevel.Warning); + return; + } + + throw; + } + } + + public virtual async Task RefreshAsync(TCacheKey key, bool? hideErrors = null, CancellationToken token = default) + { + hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; + + try + { + await Cache.RefreshAsync(NormalizeKey(key.ToString()), CancellationTokenProvider.FallbackToProvider(token)); + } + catch (Exception ex) + { + if (hideErrors == true) + { + Logger.LogException(ex, LogLevel.Warning); + return; + } + + throw; + } + } + + public virtual void Remove(TCacheKey key, bool? hideErrors = null) + { + hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; + + try + { + Cache.Remove(NormalizeKey(key.ToString())); + } + catch (Exception ex) + { + if (hideErrors == true) + { + Logger.LogException(ex, LogLevel.Warning); + } + + throw; + } + } + + public virtual async Task RemoveAsync(TCacheKey key, bool? hideErrors = null, CancellationToken token = default) + { + hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; + + try + { + await Cache.RemoveAsync(NormalizeKey(key.ToString()), CancellationTokenProvider.FallbackToProvider(token)); + } + catch (Exception ex) + { + if (hideErrors == true) + { + Logger.LogException(ex, LogLevel.Warning); + return; + } + + throw; + } + } + + } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCache.cs b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCache.cs index 23bd6f4cf2..82adeda726 100644 --- a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCache.cs +++ b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCache.cs @@ -148,4 +148,148 @@ namespace Volo.Abp.Caching CancellationToken token = default ); } + /// + /// Represents a distributed cache of type. + /// Uses a generic cache key type of type. + /// + /// The type of cache item being cached. + /// The type of cache key being used. + public interface IDistributedCache + where TCacheItem : class + { + /// + /// Gets a cache item with the given key. If no cache item is found for the given key then returns null. + /// + /// The key of cached item to be retrieved from the cache. + /// Indicates to throw or hide the exceptions for the distributed cache. + /// The cache item, or null. + TCacheItem Get( + TCacheKey key, + bool? hideErrors = null + ); + + /// + /// Gets a cache item with the given key. If no cache item is found for the given key then returns null. + /// + /// The key of cached item to be retrieved from the cache. + /// Indicates to throw or hide the exceptions for the distributed cache. + /// The for the task. + /// The cache item, or null. + Task GetAsync( + [NotNull] TCacheKey key, + bool? hideErrors = null, + CancellationToken token = default + ); + + /// + /// Gets or Adds a cache item with the given key. If no cache item is found for the given key then adds a cache item + /// provided by delegate and returns the provided cache item. + /// + /// The key of cached item to be retrieved from the cache. + /// The factory delegate is used to provide the cache item when no cache item is found for the given . + /// The cache options for the factory delegate. + /// Indicates to throw or hide the exceptions for the distributed cache. + /// The cache item. + TCacheItem GetOrAdd( + TCacheKey key, + Func factory, + Func optionsFactory = null, + bool? hideErrors = null + ); + + /// + /// Gets or Adds a cache item with the given key. If no cache item is found for the given key then adds a cache item + /// provided by delegate and returns the provided cache item. + /// + /// The key of cached item to be retrieved from the cache. + /// The factory delegate is used to provide the cache item when no cache item is found for the given . + /// The cache options for the factory delegate. + /// Indicates to throw or hide the exceptions for the distributed cache. + /// The for the task. + /// The cache item. + Task GetOrAddAsync( + [NotNull] TCacheKey key, + Func> factory, + Func optionsFactory = null, + bool? hideErrors = null, + CancellationToken token = default + ); + + /// + /// Sets the cache item value for the provided key. + /// + /// The key of cached item to be retrieved from the cache. + /// The cache item value to set in the cache. + /// The cache options for the value. + /// Indicates to throw or hide the exceptions for the distributed cache. + void Set( + TCacheKey key, + TCacheItem value, + DistributedCacheEntryOptions options = null, + bool? hideErrors = null + ); + + /// + /// Sets the cache item value for the provided key. + /// + /// The key of cached item to be retrieved from the cache. + /// The cache item value to set in the cache. + /// The cache options for the value. + /// Indicates to throw or hide the exceptions for the distributed cache. + /// The for the task. + /// The indicating that the operation is asynchronous. + Task SetAsync( + [NotNull] TCacheKey key, + [NotNull] TCacheItem value, + [CanBeNull] DistributedCacheEntryOptions options = null, + bool? hideErrors = null, + CancellationToken token = default + ); + + /// + /// Refreshes the cache value of the given key, and resets its sliding expiration timeout. + /// + /// The key of cached item to be retrieved from the cache. + /// Indicates to throw or hide the exceptions for the distributed cache. + void Refresh( + TCacheKey key, + bool? hideErrors = null + ); + + /// + /// Refreshes the cache value of the given key, and resets its sliding expiration timeout. + /// + /// The key of cached item to be retrieved from the cache. + /// Indicates to throw or hide the exceptions for the distributed cache. + /// The for the task. + /// The indicating that the operation is asynchronous. + Task RefreshAsync( + TCacheKey key, + bool? hideErrors = null, + CancellationToken token = default + ); + + /// + /// Removes the cache item for given key from cache. + /// + /// The key of cached item to be retrieved from the cache. + /// Indicates to throw or hide the exceptions for the distributed cache. + void Remove( + TCacheKey key, + bool? hideErrors = null + ); + + /// + /// Removes the cache item for given key from cache. + /// + /// The key of cached item to be retrieved from the cache. + /// Indicates to throw or hide the exceptions for the distributed cache. + /// The for the task. + /// The indicating that the operation is asynchronous. + Task RemoveAsync( + TCacheKey key, + bool? hideErrors = null, + CancellationToken token = default + ); + } } diff --git a/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs b/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs index fc6b443893..b802b3e297 100644 --- a/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs +++ b/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs @@ -122,5 +122,150 @@ namespace Volo.Abp.Caching cacheItem1.ShouldNotBeNull(); } + + [Fact] + public async Task Should_Set_Get_And_Remove_Cache_Items_With_Integer_Type_CacheKey() + { + var personCache = GetRequiredService>(); + + var cacheKey = 42; + const string personName = "john nash"; + + //Get (not exists yet) + var cacheItem = await personCache.GetAsync(cacheKey); + cacheItem.ShouldBeNull(); + + //Set + cacheItem = new PersonCacheItem(personName); + await personCache.SetAsync(cacheKey, cacheItem); + + //Get (it should be available now + cacheItem = await personCache.GetAsync(cacheKey); + cacheItem.ShouldNotBeNull(); + cacheItem.Name.ShouldBe(personName); + + //Remove + await personCache.RemoveAsync(cacheKey); + + //Get (not exists since removed) + cacheItem = await personCache.GetAsync(cacheKey); + cacheItem.ShouldBeNull(); + } + + [Fact] + public async Task GetOrAddAsync_With_Integer_Type_CacheKey() + { + var personCache = GetRequiredService>(); + + var cacheKey = 42; + const string personName = "john nash"; + + //Will execute the factory method to create the cache item + + bool factoryExecuted = false; + + var cacheItem = await personCache.GetOrAddAsync(cacheKey, + async () => + { + factoryExecuted = true; + return new PersonCacheItem(personName); + }); + + factoryExecuted.ShouldBeTrue(); + cacheItem.Name.ShouldBe(personName); + + //This time, it will not execute the factory + + factoryExecuted = false; + + cacheItem = await personCache.GetOrAddAsync(cacheKey, + async () => + { + factoryExecuted = true; + return new PersonCacheItem(personName); + }); + + factoryExecuted.ShouldBeFalse(); + cacheItem.Name.ShouldBe(personName); + } + + [Fact] + public async Task SameClassName_But_DiffNamespace_Should_Not_Use_Same_Cache_With_Integer_CacheKey() + { + var personCache = GetRequiredService>(); + var otherPersonCache = GetRequiredService>(); + + + var cacheKey = 42; + const string personName = "john nash"; + + //Get (not exists yet) + var cacheItem = await personCache.GetAsync(cacheKey); + cacheItem.ShouldBeNull(); + + var cacheItem1 = await otherPersonCache.GetAsync(cacheKey); + cacheItem1.ShouldBeNull(); + + //Set + cacheItem = new PersonCacheItem(personName); + await personCache.SetAsync(cacheKey, cacheItem); + + //Get (it should be available now, but otherPersonCache not exists now. + cacheItem = await personCache.GetAsync(cacheKey); + cacheItem.ShouldNotBeNull(); + cacheItem.Name.ShouldBe(personName); + + cacheItem1 = await otherPersonCache.GetAsync(cacheKey); + cacheItem1.ShouldBeNull(); + + //set other person cache + cacheItem1 = new Sail.Testing.Caching.PersonCacheItem(personName); + await otherPersonCache.SetAsync(cacheKey, cacheItem1); + + cacheItem1 = await otherPersonCache.GetAsync(cacheKey); + cacheItem1.ShouldNotBeNull(); + cacheItem1.Name.ShouldBe(personName); + + //Remove + await personCache.RemoveAsync(cacheKey); + + + //Get (not exists since removed) + cacheItem = await personCache.GetAsync(cacheKey); + cacheItem.ShouldBeNull(); + + cacheItem1 = await otherPersonCache.GetAsync(cacheKey); + cacheItem1.ShouldNotBeNull(); + + } + + [Fact] + public async Task Should_Set_Get_And_Remove_Cache_Items_With_Object_Type_CacheKey() + { + var personCache = GetRequiredService>(); + + var cacheKey = new DummyObjectAsCacheKey { DummyData = "DummyData", DummyInt = 42 }; + const string personName = "john nash"; + + //Get (not exists yet) + var cacheItem = await personCache.GetAsync(cacheKey); + cacheItem.ShouldBeNull(); + + //Set + cacheItem = new PersonCacheItem(personName); + await personCache.SetAsync(cacheKey, cacheItem); + + //Get (it should be available now + cacheItem = await personCache.GetAsync(cacheKey); + cacheItem.ShouldNotBeNull(); + cacheItem.Name.ShouldBe(personName); + + //Remove + await personCache.RemoveAsync(cacheKey); + + //Get (not exists since removed) + cacheItem = await personCache.GetAsync(cacheKey); + cacheItem.ShouldBeNull(); + } } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/PersonCacheItem.cs b/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/PersonCacheItem.cs index b6c6f1dd0a..6b3d9c36df 100644 --- a/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/PersonCacheItem.cs +++ b/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/PersonCacheItem.cs @@ -17,7 +17,14 @@ namespace Volo.Abp.Caching Name = name; } } + + public class DummyObjectAsCacheKey + { + public string DummyData { get; set; } + public int DummyInt { get; set; } + } } + namespace Sail.Testing.Caching { [Serializable] From 14ea3f2f097c8aae695745eb09da584f4a113170 Mon Sep 17 00:00:00 2001 From: gterdem Date: Tue, 15 Oct 2019 13:14:10 +0300 Subject: [PATCH 2/3] Implemented inheritance for DistributedCache and interface. Fixed issue with complex object ToString resulting same object name as CacheKey. --- .../Volo/Abp/Caching/DistributedCache.cs | 494 ++++-------------- .../Volo/Abp/Caching/IDistributedCache.cs | 135 +---- .../Abp/Caching/DistributedCache_Tests.cs | 42 ++ 3 files changed, 147 insertions(+), 524 deletions(-) diff --git a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs index 654e60f323..be8fde19f2 100644 --- a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs +++ b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Caching.Distributed; @@ -15,10 +16,36 @@ namespace Volo.Abp.Caching /// Represents a distributed cache of type. /// /// The type of cache item being cached. - public class DistributedCache : IDistributedCache + public class DistributedCache : DistributedCache, IDistributedCache where TCacheItem : class { - public ILogger> Logger { get; set; } + public DistributedCache( + IOptions cacheOption, + IOptions distributedCacheOption, + IDistributedCache cache, + ICancellationTokenProvider cancellationTokenProvider, + IDistributedCacheSerializer serializer, + ICurrentTenant currentTenant) : base( + cacheOption: cacheOption, + distributedCacheOption: distributedCacheOption, + cache: cache, + cancellationTokenProvider: cancellationTokenProvider, + serializer: serializer, + currentTenant: currentTenant) + { + } + + } + /// + /// Represents a distributed cache of type. + /// Uses a generic cache key type of type. + /// + /// The type of cache item being cached. + /// The type of cache key being used. + public class DistributedCache : IDistributedCache + where TCacheItem : class + { + public ILogger> Logger { get; set; } protected string CacheName { get; set; } @@ -52,7 +79,7 @@ namespace Volo.Abp.Caching _cacheOption = cacheOption.Value; Cache = cache; CancellationTokenProvider = cancellationTokenProvider; - Logger = NullLogger>.Instance; + Logger = NullLogger>.Instance; Serializer = serializer; CurrentTenant = currentTenant; @@ -60,7 +87,60 @@ namespace Volo.Abp.Caching SetDefaultOptions(); } + protected virtual string NormalizeKey(TCacheKey key) + { + Type type = key.GetType(); + string keyValue = key.ToString(); + + // If complex type of object, override the key value with property concatenation + if (!typeof(IComparable).IsAssignableFrom(type) || type.IsPrimitive || type.IsValueType) + { + var sb = new System.Text.StringBuilder(); + var properties = type.GetProperties().Where(prop => prop.CanRead && prop.CanWrite); + + foreach (var prop in properties) + { + var value = prop.GetValue(key, null); + if (value != null) + { + sb.Append(value.ToString()); + } + } + keyValue = sb.ToString(); + } + var normalizedKey = "c:" + CacheName + ",k:" + _cacheOption.KeyPrefix + keyValue; + + if (!IgnoreMultiTenancy && CurrentTenant.Id.HasValue) + { + normalizedKey = "t:" + CurrentTenant.Id.Value + "," + normalizedKey; + } + + return normalizedKey; + } + + protected virtual DistributedCacheEntryOptions GetDefaultCacheEntryOptions() + { + foreach (var configure in _cacheOption.CacheConfigurators) + { + var options = configure.Invoke(CacheName); + if (options != null) + { + return options; + } + } + return _cacheOption.GlobalCacheEntryOptions; + } + + protected virtual void SetDefaultOptions() + { + CacheName = CacheNameAttribute.GetCacheName(typeof(TCacheItem)); + + //IgnoreMultiTenancy + IgnoreMultiTenancy = typeof(TCacheItem).IsDefined(typeof(IgnoreMultiTenancyAttribute), true); + //Configure default cache entry options + DefaultCacheOptions = GetDefaultCacheEntryOptions(); + } /// /// Gets a cache item with the given key. If no cache item is found for the given key then returns null. /// @@ -68,7 +148,7 @@ namespace Volo.Abp.Caching /// Indicates to throw or hide the exceptions for the distributed cache. /// The cache item, or null. public virtual TCacheItem Get( - string key, + TCacheKey key, bool? hideErrors = null) { hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; @@ -106,7 +186,7 @@ namespace Volo.Abp.Caching /// The for the task. /// The cache item, or null. public virtual async Task GetAsync( - string key, + TCacheKey key, bool? hideErrors = null, CancellationToken token = default) { @@ -131,7 +211,7 @@ namespace Volo.Abp.Caching throw; } - + if (cachedBytes == null) { return null; @@ -139,7 +219,6 @@ namespace Volo.Abp.Caching return Serializer.Deserialize(cachedBytes); } - /// /// Gets or Adds a cache item with the given key. If no cache item is found for the given key then adds a cache item /// provided by delegate and returns the provided cache item. @@ -149,10 +228,10 @@ namespace Volo.Abp.Caching /// The cache options for the factory delegate. /// Indicates to throw or hide the exceptions for the distributed cache. /// The cache item. - public TCacheItem GetOrAdd( - string key, - Func factory, - Func optionsFactory = null, + public virtual TCacheItem GetOrAdd( + TCacheKey key, + Func factory, + Func optionsFactory = null, bool? hideErrors = null) { var value = Get(key, hideErrors); @@ -175,7 +254,6 @@ namespace Volo.Abp.Caching return value; } - /// /// Gets or Adds a cache item with the given key. If no cache item is found for the given key then adds a cache item /// provided by delegate and returns the provided cache item. @@ -186,11 +264,11 @@ namespace Volo.Abp.Caching /// Indicates to throw or hide the exceptions for the distributed cache. /// The for the task. /// The cache item. - public async Task GetOrAddAsync( - string key, - Func> factory, - Func optionsFactory = null, - bool? hideErrors = null, + public virtual async Task GetOrAddAsync( + TCacheKey key, + Func> factory, + Func optionsFactory = null, + bool? hideErrors = null, CancellationToken token = default) { token = CancellationTokenProvider.FallbackToProvider(token); @@ -214,7 +292,6 @@ namespace Volo.Abp.Caching return value; } - /// /// Sets the cache item value for the provided key. /// @@ -223,7 +300,7 @@ namespace Volo.Abp.Caching /// The cache options for the value. /// Indicates to throw or hide the exceptions for the distributed cache. public virtual void Set( - string key, + TCacheKey key, TCacheItem value, DistributedCacheEntryOptions options = null, bool? hideErrors = null) @@ -249,7 +326,6 @@ namespace Volo.Abp.Caching throw; } } - /// /// Sets the cache item value for the provided key. /// @@ -260,7 +336,7 @@ namespace Volo.Abp.Caching /// The for the task. /// The indicating that the operation is asynchronous. public virtual async Task SetAsync( - string key, + TCacheKey key, TCacheItem value, DistributedCacheEntryOptions options = null, bool? hideErrors = null, @@ -288,15 +364,14 @@ namespace Volo.Abp.Caching throw; } } - /// /// Refreshes the cache value of the given key, and resets its sliding expiration timeout. /// /// The key of cached item to be retrieved from the cache. /// Indicates to throw or hide the exceptions for the distributed cache. public virtual void Refresh( - string key, - bool? hideErrors = null) + TCacheKey key, bool? + hideErrors = null) { hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; @@ -315,7 +390,6 @@ namespace Volo.Abp.Caching throw; } } - /// /// Refreshes the cache value of the given key, and resets its sliding expiration timeout. /// @@ -324,7 +398,7 @@ namespace Volo.Abp.Caching /// The for the task. /// The indicating that the operation is asynchronous. public virtual async Task RefreshAsync( - string key, + TCacheKey key, bool? hideErrors = null, CancellationToken token = default) { @@ -345,15 +419,13 @@ namespace Volo.Abp.Caching throw; } } - - /// /// Removes the cache item for given key from cache. /// /// The key of cached item to be retrieved from the cache. /// Indicates to throw or hide the exceptions for the distributed cache. public virtual void Remove( - string key, + TCacheKey key, bool? hideErrors = null) { hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; @@ -372,7 +444,6 @@ namespace Volo.Abp.Caching throw; } } - /// /// Removes the cache item for given key from cache. /// @@ -381,7 +452,7 @@ namespace Volo.Abp.Caching /// The for the task. /// The indicating that the operation is asynchronous. public virtual async Task RemoveAsync( - string key, + TCacheKey key, bool? hideErrors = null, CancellationToken token = default) { @@ -402,364 +473,7 @@ namespace Volo.Abp.Caching throw; } } - - protected virtual string NormalizeKey(string key) - { - var normalizedKey = "c:" + CacheName + ",k:" + _cacheOption.KeyPrefix + key; - - if (!IgnoreMultiTenancy && CurrentTenant.Id.HasValue) - { - normalizedKey = "t:" + CurrentTenant.Id.Value + "," + normalizedKey; - } - - return normalizedKey; - } - - protected virtual DistributedCacheEntryOptions GetDefaultCacheEntryOptions() - { - foreach (var configure in _cacheOption.CacheConfigurators) - { - var options = configure.Invoke(CacheName); - if (options != null) - { - return options; - } - } - return _cacheOption.GlobalCacheEntryOptions; - } - - protected virtual void SetDefaultOptions() - { - CacheName = CacheNameAttribute.GetCacheName(typeof(TCacheItem)); - - //IgnoreMultiTenancy - IgnoreMultiTenancy = typeof(TCacheItem).IsDefined(typeof(IgnoreMultiTenancyAttribute), true); - - //Configure default cache entry options - DefaultCacheOptions = GetDefaultCacheEntryOptions(); - } - } - /// - /// Represents a distributed cache of type. - /// Uses a generic cache key type of type. - /// - /// The type of cache item being cached. - /// The type of cache key being used. - public class DistributedCache : IDistributedCache - where TCacheItem : class - { - public ILogger> Logger { get; set; } - - protected string CacheName { get; set; } - - protected bool IgnoreMultiTenancy { get; set; } - - protected IDistributedCache Cache { get; } - - protected ICancellationTokenProvider CancellationTokenProvider { get; } - - protected IDistributedCacheSerializer Serializer { get; } - - protected ICurrentTenant CurrentTenant { get; } - - protected SemaphoreSlim SyncSemaphore { get; } - - protected DistributedCacheEntryOptions DefaultCacheOptions; - - private readonly CacheOptions _cacheOption; - - private readonly DistributedCacheOptions _distributedCacheOption; - - public DistributedCache( - IOptions cacheOption, - IOptions distributedCacheOption, - IDistributedCache cache, - ICancellationTokenProvider cancellationTokenProvider, - IDistributedCacheSerializer serializer, - ICurrentTenant currentTenant) - { - _distributedCacheOption = distributedCacheOption.Value; - _cacheOption = cacheOption.Value; - Cache = cache; - CancellationTokenProvider = cancellationTokenProvider; - Logger = NullLogger>.Instance; - Serializer = serializer; - CurrentTenant = currentTenant; - - SyncSemaphore = new SemaphoreSlim(1, 1); - - SetDefaultOptions(); - } - protected virtual string NormalizeKey(string key) - { - var normalizedKey = "c:" + CacheName + ",k:" + _cacheOption.KeyPrefix + key; - - if (!IgnoreMultiTenancy && CurrentTenant.Id.HasValue) - { - normalizedKey = "t:" + CurrentTenant.Id.Value + "," + normalizedKey; - } - - return normalizedKey; - } - - protected virtual DistributedCacheEntryOptions GetDefaultCacheEntryOptions() - { - foreach (var configure in _cacheOption.CacheConfigurators) - { - var options = configure.Invoke(CacheName); - if (options != null) - { - return options; - } - } - return _cacheOption.GlobalCacheEntryOptions; - } - - protected virtual void SetDefaultOptions() - { - CacheName = CacheNameAttribute.GetCacheName(typeof(TCacheItem)); - - //IgnoreMultiTenancy - IgnoreMultiTenancy = typeof(TCacheItem).IsDefined(typeof(IgnoreMultiTenancyAttribute), true); - - //Configure default cache entry options - DefaultCacheOptions = GetDefaultCacheEntryOptions(); - } - public virtual TCacheItem Get(TCacheKey key, bool? hideErrors = null) - { - hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; - - byte[] cachedBytes; - - try - { - cachedBytes = Cache.Get(NormalizeKey(key?.ToString())); - } - catch (Exception ex) - { - if (hideErrors == true) - { - Logger.LogException(ex, LogLevel.Warning); - return null; - } - - throw; - } - - if (cachedBytes == null) - { - return null; - } - - return Serializer.Deserialize(cachedBytes); - } - - public virtual async Task GetAsync(TCacheKey key, bool? hideErrors = null, CancellationToken token = default) - { - hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; - - byte[] cachedBytes; - - try - { - cachedBytes = await Cache.GetAsync( - NormalizeKey(key.ToString()), - CancellationTokenProvider.FallbackToProvider(token) - ); - } - catch (Exception ex) - { - if (hideErrors == true) - { - Logger.LogException(ex, LogLevel.Warning); - return null; - } - - throw; - } - - if (cachedBytes == null) - { - return null; - } - - return Serializer.Deserialize(cachedBytes); - } - - public virtual TCacheItem GetOrAdd(TCacheKey key, Func factory, Func optionsFactory = null, bool? hideErrors = null) - { - var value = Get(key, hideErrors); - if (value != null) - { - return value; - } - - using (SyncSemaphore.Lock()) - { - value = Get(key, hideErrors); - if (value != null) - { - return value; - } - - value = factory(); - Set(key, value, optionsFactory?.Invoke(), hideErrors); - } - - return value; - } - - public virtual async Task GetOrAddAsync(TCacheKey key, Func> factory, Func optionsFactory = null, bool? hideErrors = null, CancellationToken token = default) - { - token = CancellationTokenProvider.FallbackToProvider(token); - var value = await GetAsync(key, hideErrors, token); - if (value != null) - { - return value; - } - - using (await SyncSemaphore.LockAsync(token)) - { - value = await GetAsync(key, hideErrors, token); - if (value != null) - { - return value; - } - - value = await factory(); - await SetAsync(key, value, optionsFactory?.Invoke(), hideErrors, token); - } - - return value; - } - - public virtual void Set(TCacheKey key, TCacheItem value, DistributedCacheEntryOptions options = null, bool? hideErrors = null) - { - hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; - - try - { - Cache.Set( - NormalizeKey(key.ToString()), - Serializer.Serialize(value), - options ?? DefaultCacheOptions - ); - } - catch (Exception ex) - { - if (hideErrors == true) - { - Logger.LogException(ex, LogLevel.Warning); - return; - } - - throw; - } - } - - public virtual async Task SetAsync(TCacheKey key, TCacheItem value, DistributedCacheEntryOptions options = null, bool? hideErrors = null, CancellationToken token = default) - { - hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; - - try - { - await Cache.SetAsync( - NormalizeKey(key.ToString()), - Serializer.Serialize(value), - options ?? DefaultCacheOptions, - CancellationTokenProvider.FallbackToProvider(token) - ); - } - catch (Exception ex) - { - if (hideErrors == true) - { - Logger.LogException(ex, LogLevel.Warning); - return; - } - - throw; - } - } - - public virtual void Refresh(TCacheKey key, bool? hideErrors = null) - { - hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; - - try - { - Cache.Refresh(NormalizeKey(key.ToString())); - } - catch (Exception ex) - { - if (hideErrors == true) - { - Logger.LogException(ex, LogLevel.Warning); - return; - } - - throw; - } - } - - public virtual async Task RefreshAsync(TCacheKey key, bool? hideErrors = null, CancellationToken token = default) - { - hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; - - try - { - await Cache.RefreshAsync(NormalizeKey(key.ToString()), CancellationTokenProvider.FallbackToProvider(token)); - } - catch (Exception ex) - { - if (hideErrors == true) - { - Logger.LogException(ex, LogLevel.Warning); - return; - } - - throw; - } - } - - public virtual void Remove(TCacheKey key, bool? hideErrors = null) - { - hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; - - try - { - Cache.Remove(NormalizeKey(key.ToString())); - } - catch (Exception ex) - { - if (hideErrors == true) - { - Logger.LogException(ex, LogLevel.Warning); - } - - throw; - } - } - - public virtual async Task RemoveAsync(TCacheKey key, bool? hideErrors = null, CancellationToken token = default) - { - hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; - - try - { - await Cache.RemoveAsync(NormalizeKey(key.ToString()), CancellationTokenProvider.FallbackToProvider(token)); - } - catch (Exception ex) - { - if (hideErrors == true) - { - Logger.LogException(ex, LogLevel.Warning); - return; - } - - throw; - } - } - + } + } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCache.cs b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCache.cs index 82adeda726..163da05632 100644 --- a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCache.cs +++ b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCache.cs @@ -10,143 +10,10 @@ namespace Volo.Abp.Caching /// Represents a distributed cache of type. /// /// The type of cache item being cached. - public interface IDistributedCache + public interface IDistributedCache : IDistributedCache where TCacheItem : class { - /// - /// Gets a cache item with the given key. If no cache item is found for the given key then returns null. - /// - /// The key of cached item to be retrieved from the cache. - /// Indicates to throw or hide the exceptions for the distributed cache. - /// The cache item, or null. - TCacheItem Get( - string key, - bool? hideErrors = null - ); - - /// - /// Gets a cache item with the given key. If no cache item is found for the given key then returns null. - /// - /// The key of cached item to be retrieved from the cache. - /// Indicates to throw or hide the exceptions for the distributed cache. - /// The for the task. - /// The cache item, or null. - Task GetAsync( - [NotNull] string key, - bool? hideErrors = null, - CancellationToken token = default - ); - - /// - /// Gets or Adds a cache item with the given key. If no cache item is found for the given key then adds a cache item - /// provided by delegate and returns the provided cache item. - /// - /// The key of cached item to be retrieved from the cache. - /// The factory delegate is used to provide the cache item when no cache item is found for the given . - /// The cache options for the factory delegate. - /// Indicates to throw or hide the exceptions for the distributed cache. - /// The cache item. - TCacheItem GetOrAdd( - string key, - Func factory, - Func optionsFactory = null, - bool? hideErrors = null - ); - /// - /// Gets or Adds a cache item with the given key. If no cache item is found for the given key then adds a cache item - /// provided by delegate and returns the provided cache item. - /// - /// The key of cached item to be retrieved from the cache. - /// The factory delegate is used to provide the cache item when no cache item is found for the given . - /// The cache options for the factory delegate. - /// Indicates to throw or hide the exceptions for the distributed cache. - /// The for the task. - /// The cache item. - Task GetOrAddAsync( - [NotNull] string key, - Func> factory, - Func optionsFactory = null, - bool? hideErrors = null, - CancellationToken token = default - ); - - /// - /// Sets the cache item value for the provided key. - /// - /// The key of cached item to be retrieved from the cache. - /// The cache item value to set in the cache. - /// The cache options for the value. - /// Indicates to throw or hide the exceptions for the distributed cache. - void Set( - string key, - TCacheItem value, - DistributedCacheEntryOptions options = null, - bool? hideErrors = null - ); - - /// - /// Sets the cache item value for the provided key. - /// - /// The key of cached item to be retrieved from the cache. - /// The cache item value to set in the cache. - /// The cache options for the value. - /// Indicates to throw or hide the exceptions for the distributed cache. - /// The for the task. - /// The indicating that the operation is asynchronous. - Task SetAsync( - [NotNull] string key, - [NotNull] TCacheItem value, - [CanBeNull] DistributedCacheEntryOptions options = null, - bool? hideErrors = null, - CancellationToken token = default - ); - - /// - /// Refreshes the cache value of the given key, and resets its sliding expiration timeout. - /// - /// The key of cached item to be retrieved from the cache. - /// Indicates to throw or hide the exceptions for the distributed cache. - void Refresh( - string key, - bool? hideErrors = null - ); - - /// - /// Refreshes the cache value of the given key, and resets its sliding expiration timeout. - /// - /// The key of cached item to be retrieved from the cache. - /// Indicates to throw or hide the exceptions for the distributed cache. - /// The for the task. - /// The indicating that the operation is asynchronous. - Task RefreshAsync( - string key, - bool? hideErrors = null, - CancellationToken token = default - ); - - /// - /// Removes the cache item for given key from cache. - /// - /// The key of cached item to be retrieved from the cache. - /// Indicates to throw or hide the exceptions for the distributed cache. - void Remove( - string key, - bool? hideErrors = null - ); - - /// - /// Removes the cache item for given key from cache. - /// - /// The key of cached item to be retrieved from the cache. - /// Indicates to throw or hide the exceptions for the distributed cache. - /// The for the task. - /// The indicating that the operation is asynchronous. - Task RemoveAsync( - string key, - bool? hideErrors = null, - CancellationToken token = default - ); } /// /// Represents a distributed cache of type. diff --git a/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs b/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs index b802b3e297..93788e0995 100644 --- a/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs +++ b/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs @@ -267,5 +267,47 @@ namespace Volo.Abp.Caching cacheItem = await personCache.GetAsync(cacheKey); cacheItem.ShouldBeNull(); } + + [Fact] + public async Task Should_Set_Get_And_Remove_Cache_Items_For_Same_Object_Type_With_Different_CacheKeys() + { + var personCache = GetRequiredService>(); + + var cache1Key = new DummyObjectAsCacheKey { DummyData = "DummyData", DummyInt = 42 }; + var cache2Key = new DummyObjectAsCacheKey { DummyData = "DummyData2", DummyInt = 24 }; + const string personName = "john nash"; + + //Get (not exists yet) + var cacheItem1 = await personCache.GetAsync(cache1Key); + var cacheItem2 = await personCache.GetAsync(cache2Key); + cacheItem1.ShouldBeNull(); + cacheItem2.ShouldBeNull(); + + //Set + cacheItem1 = new PersonCacheItem(personName); + cacheItem2 = new PersonCacheItem(personName); + await personCache.SetAsync(cache1Key, cacheItem1); + await personCache.SetAsync(cache2Key, cacheItem2); + + //Get (it should be available now + cacheItem1 = await personCache.GetAsync(cache1Key); + cacheItem1.ShouldNotBeNull(); + cacheItem1.Name.ShouldBe(personName); + + cacheItem2 = await personCache.GetAsync(cache2Key); + cacheItem2.ShouldNotBeNull(); + cacheItem2.Name.ShouldBe(personName); + + //Remove + await personCache.RemoveAsync(cache1Key); + await personCache.RemoveAsync(cache2Key); + + //Get (not exists since removed) + cacheItem1 = await personCache.GetAsync(cache1Key); + cacheItem1.ShouldBeNull(); + cacheItem2 = await personCache.GetAsync(cache2Key); + cacheItem2.ShouldBeNull(); + } + } } \ No newline at end of file From 412bfd5a9883f71fd3e3e30ec0a6064b61c7191e Mon Sep 17 00:00:00 2001 From: Galip Tolga Erdem Date: Sat, 19 Oct 2019 16:52:35 +0300 Subject: [PATCH 3/3] Complex object key calculation reverted. Overriding ToString method of complex object to be used as key as suggested. --- .../Volo/Abp/Caching/DistributedCache.cs | 82 +++++++------------ .../Abp/Caching/DistributedCache_Tests.cs | 10 +-- .../Volo/Abp/Caching/PersonCacheItem.cs | 28 ++++++- 3 files changed, 60 insertions(+), 60 deletions(-) diff --git a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs index be8fde19f2..feef4f889b 100644 --- a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs +++ b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Caching.Distributed; @@ -44,7 +43,7 @@ namespace Volo.Abp.Caching /// The type of cache key being used. public class DistributedCache : IDistributedCache where TCacheItem : class - { + { public ILogger> Logger { get; set; } protected string CacheName { get; set; } @@ -88,27 +87,8 @@ namespace Volo.Abp.Caching SetDefaultOptions(); } protected virtual string NormalizeKey(TCacheKey key) - { - Type type = key.GetType(); - string keyValue = key.ToString(); - - // If complex type of object, override the key value with property concatenation - if (!typeof(IComparable).IsAssignableFrom(type) || type.IsPrimitive || type.IsValueType) - { - var sb = new System.Text.StringBuilder(); - var properties = type.GetProperties().Where(prop => prop.CanRead && prop.CanWrite); - - foreach (var prop in properties) - { - var value = prop.GetValue(key, null); - if (value != null) - { - sb.Append(value.ToString()); - } - } - keyValue = sb.ToString(); - } - var normalizedKey = "c:" + CacheName + ",k:" + _cacheOption.KeyPrefix + keyValue; + { + var normalizedKey = "c:" + CacheName + ",k:" + _cacheOption.KeyPrefix + key.ToString(); if (!IgnoreMultiTenancy && CurrentTenant.Id.HasValue) { @@ -116,7 +96,7 @@ namespace Volo.Abp.Caching } return normalizedKey; - } + } protected virtual DistributedCacheEntryOptions GetDefaultCacheEntryOptions() { @@ -148,7 +128,7 @@ namespace Volo.Abp.Caching /// Indicates to throw or hide the exceptions for the distributed cache. /// The cache item, or null. public virtual TCacheItem Get( - TCacheKey key, + TCacheKey key, bool? hideErrors = null) { hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; @@ -186,8 +166,8 @@ namespace Volo.Abp.Caching /// The for the task. /// The cache item, or null. public virtual async Task GetAsync( - TCacheKey key, - bool? hideErrors = null, + TCacheKey key, + bool? hideErrors = null, CancellationToken token = default) { hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; @@ -229,9 +209,9 @@ namespace Volo.Abp.Caching /// Indicates to throw or hide the exceptions for the distributed cache. /// The cache item. public virtual TCacheItem GetOrAdd( - TCacheKey key, - Func factory, - Func optionsFactory = null, + TCacheKey key, + Func factory, + Func optionsFactory = null, bool? hideErrors = null) { var value = Get(key, hideErrors); @@ -265,10 +245,10 @@ namespace Volo.Abp.Caching /// The for the task. /// The cache item. public virtual async Task GetOrAddAsync( - TCacheKey key, - Func> factory, - Func optionsFactory = null, - bool? hideErrors = null, + TCacheKey key, + Func> factory, + Func optionsFactory = null, + bool? hideErrors = null, CancellationToken token = default) { token = CancellationTokenProvider.FallbackToProvider(token); @@ -300,9 +280,9 @@ namespace Volo.Abp.Caching /// The cache options for the value. /// Indicates to throw or hide the exceptions for the distributed cache. public virtual void Set( - TCacheKey key, - TCacheItem value, - DistributedCacheEntryOptions options = null, + TCacheKey key, + TCacheItem value, + DistributedCacheEntryOptions options = null, bool? hideErrors = null) { hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; @@ -336,10 +316,10 @@ namespace Volo.Abp.Caching /// The for the task. /// The indicating that the operation is asynchronous. public virtual async Task SetAsync( - TCacheKey key, - TCacheItem value, - DistributedCacheEntryOptions options = null, - bool? hideErrors = null, + TCacheKey key, + TCacheItem value, + DistributedCacheEntryOptions options = null, + bool? hideErrors = null, CancellationToken token = default) { hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; @@ -370,7 +350,7 @@ namespace Volo.Abp.Caching /// The key of cached item to be retrieved from the cache. /// Indicates to throw or hide the exceptions for the distributed cache. public virtual void Refresh( - TCacheKey key, bool? + TCacheKey key, bool? hideErrors = null) { hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; @@ -398,8 +378,8 @@ namespace Volo.Abp.Caching /// The for the task. /// The indicating that the operation is asynchronous. public virtual async Task RefreshAsync( - TCacheKey key, - bool? hideErrors = null, + TCacheKey key, + bool? hideErrors = null, CancellationToken token = default) { hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; @@ -425,7 +405,7 @@ namespace Volo.Abp.Caching /// The key of cached item to be retrieved from the cache. /// Indicates to throw or hide the exceptions for the distributed cache. public virtual void Remove( - TCacheKey key, + TCacheKey key, bool? hideErrors = null) { hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; @@ -452,8 +432,8 @@ namespace Volo.Abp.Caching /// The for the task. /// The indicating that the operation is asynchronous. public virtual async Task RemoveAsync( - TCacheKey key, - bool? hideErrors = null, + TCacheKey key, + bool? hideErrors = null, CancellationToken token = default) { hideErrors = hideErrors ?? _distributedCacheOption.HideErrors; @@ -472,8 +452,8 @@ namespace Volo.Abp.Caching throw; } - } - - } - + } + + } + } \ No newline at end of file diff --git a/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs b/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs index 93788e0995..927448463a 100644 --- a/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs +++ b/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs @@ -242,9 +242,9 @@ namespace Volo.Abp.Caching [Fact] public async Task Should_Set_Get_And_Remove_Cache_Items_With_Object_Type_CacheKey() { - var personCache = GetRequiredService>(); + var personCache = GetRequiredService>(); - var cacheKey = new DummyObjectAsCacheKey { DummyData = "DummyData", DummyInt = 42 }; + var cacheKey = new ComplexObjectAsCacheKey { Name = "DummyData", Age = 42 }; const string personName = "john nash"; //Get (not exists yet) @@ -271,10 +271,10 @@ namespace Volo.Abp.Caching [Fact] public async Task Should_Set_Get_And_Remove_Cache_Items_For_Same_Object_Type_With_Different_CacheKeys() { - var personCache = GetRequiredService>(); + var personCache = GetRequiredService>(); - var cache1Key = new DummyObjectAsCacheKey { DummyData = "DummyData", DummyInt = 42 }; - var cache2Key = new DummyObjectAsCacheKey { DummyData = "DummyData2", DummyInt = 24 }; + var cache1Key = new ComplexObjectAsCacheKey { Name = "John", Age = 42 }; + var cache2Key = new ComplexObjectAsCacheKey { Name = "Jenny", Age = 24 }; const string personName = "john nash"; //Get (not exists yet) diff --git a/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/PersonCacheItem.cs b/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/PersonCacheItem.cs index 6b3d9c36df..7ea37ffd26 100644 --- a/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/PersonCacheItem.cs +++ b/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/PersonCacheItem.cs @@ -1,5 +1,6 @@ using System; - +using System.Linq; + namespace Volo.Abp.Caching { [Serializable] @@ -18,10 +19,29 @@ namespace Volo.Abp.Caching } } - public class DummyObjectAsCacheKey + public class ComplexObjectAsCacheKey { - public string DummyData { get; set; } - public int DummyInt { get; set; } + public string Name { get; set; } + public int Age { get; set; } + + public override string ToString() + { + // Return selective fields + //return $"{Name}_{Age}"; + // Return all the fields concatenated + var sb = new System.Text.StringBuilder(); + var properties = this.GetType().GetProperties() + .Where(prop => prop.CanRead && prop.CanWrite); + foreach (var prop in properties) + { + var value = prop.GetValue(this, null); + if (value != null) + { + sb.Append(value.ToString()); + } + } + return sb.ToString(); + } } }