From 250f2d1f8aba530397c2d492c7a72f203249f192 Mon Sep 17 00:00:00 2001 From: Halil ibrahim Kalkan Date: Sat, 21 Jul 2018 20:09:44 +0300 Subject: [PATCH] Add GetOrAddAsync to DistributedCache. --- .../Volo/Abp/Caching/DistributedCache.cs | 52 ++++++++++++++++++- .../Volo/Abp/Caching/IDistributedCache.cs | 14 ++++- .../Volo/Abp/Localization/LanguageInfo.cs | 6 +++ .../Abp/Caching/DistributedCache_Tests.cs | 37 +++++++++++++ 4 files changed, 107 insertions(+), 2 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 26d2b1f24b..b8b897068f 100644 --- a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs +++ b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Caching.Distributed; +using Nito.AsyncEx; using Volo.Abp.MultiTenancy; using Volo.Abp.Serialization; using Volo.Abp.Threading; @@ -24,10 +25,12 @@ namespace Volo.Abp.Caching protected ICurrentTenant CurrentTenant { get; } + protected AsyncLock AsyncLock { get; } = new AsyncLock(); + public DistributedCache( IDistributedCache cache, ICancellationTokenProvider cancellationTokenProvider, - IObjectSerializer objectSerializer, + IObjectSerializer objectSerializer, ICurrentTenant currentTenant) { Cache = cache; @@ -60,6 +63,53 @@ namespace Volo.Abp.Caching return ObjectSerializer.Deserialize(cachedBytes); } + public TCacheItem GetOrAdd(string key, Func factory) + { + var value = Get(key); + if (value != null) + { + return value; + } + + using (AsyncLock.Lock()) + { + value = Get(key); + if (value != null) + { + return value; + } + + value = factory(); + Set(key, value); + + } + + return value; + } + + public async Task GetOrAddAsync(string key, Func> factory, CancellationToken token = default) + { + var value = await GetAsync(key, token); + if (value != null) + { + return value; + } + + using (await AsyncLock.LockAsync(token)) + { + value = await GetAsync(key, token); + if (value != null) + { + return value; + } + + value = await factory(); + await SetAsync(key, value, token: token); + } + + return value; + } + public virtual void Set(string key, TCacheItem value, DistributedCacheEntryOptions options = null) { Cache.Set( 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 805e721b0c..5fd6d2d84f 100644 --- a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCache.cs +++ b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCache.cs @@ -1,4 +1,5 @@ -using System.Threading; +using System; +using System.Threading; using System.Threading.Tasks; using JetBrains.Annotations; using Microsoft.Extensions.Caching.Distributed; @@ -17,6 +18,17 @@ namespace Volo.Abp.Caching CancellationToken token = default ); + TCacheItem GetOrAdd( + string key, + Func factory + ); + + Task GetOrAddAsync( + [NotNull] string key, + Func> factory, + CancellationToken token = default + ); + void Set( string key, TCacheItem value, diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LanguageInfo.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LanguageInfo.cs index 05c243f92c..7084e7205c 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LanguageInfo.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LanguageInfo.cs @@ -3,6 +3,7 @@ using JetBrains.Annotations; namespace Volo.Abp.Localization { + [Serializable] public class LanguageInfo { [NotNull] @@ -17,6 +18,11 @@ namespace Volo.Abp.Localization [CanBeNull] public virtual string FlagIcon { get; set; } + protected LanguageInfo() + { + + } + public LanguageInfo( string cultureName, string uiCultureName = null, 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 23169eb240..4beca1f32b 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 @@ -35,5 +35,42 @@ namespace Volo.Abp.Caching cacheItem = await personCache.GetAsync(cacheKey); cacheItem.ShouldBeNull(); } + + [Fact] + public async Task GetOrAddAsync() + { + var personCache = GetRequiredService>(); + + var cacheKey = Guid.NewGuid().ToString(); + 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); + } } }