Skip to content

Commit 3a8f822

Browse files
authored
feat(ICacheManager): add prefix cache key (#5210)
* doc: 更新示例 * refactor: 增加内部缓存策略 * refactor: 增加空文化判断 * test: 更新单元测试 * test: 更新单元测试 * refactor: 增加前缀
1 parent 692d46c commit 3a8f822

File tree

4 files changed

+48
-20
lines changed

4 files changed

+48
-20
lines changed

src/BootstrapBlazor.Server/Components/Samples/Searches.razor.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ private async Task<IEnumerable<Foo>> OnSearchFoo(string searchText)
6969
}).ToList();
7070
}
7171

72-
private async Task<IEnumerable<string>> OnModelSearch(string v)
72+
private async Task<IEnumerable<string?>> OnModelSearch(string v)
7373
{
7474
// 模拟异步延时
7575
await Task.Delay(100);

src/BootstrapBlazor/Services/CacheManager.cs

+25-17
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ internal class CacheManager : ICacheManager
2929
[NotNull]
3030
private static CacheManager? Instance { get; set; }
3131

32+
private const string CacheKeyPrefix = "BootstrapBlazor";
33+
3234
/// <summary>
3335
/// 构造函数
3436
/// </summary>
@@ -60,11 +62,13 @@ public TItem GetOrCreate<TItem>(object key, Func<ICacheEntry, TItem> factory) =>
6062
/// </summary>
6163
public Task<TItem> GetOrCreateAsync<TItem>(object key, Func<ICacheEntry, Task<TItem>> factory) => Cache.GetOrCreateAsync(key, async entry =>
6264
{
63-
if (key is not string)
65+
var item = await factory(entry);
66+
67+
if (entry.SlidingExpiration == null && entry.AbsoluteExpiration == null && entry.Priority != CacheItemPriority.NeverRemove)
6468
{
6569
entry.SetSlidingExpiration(TimeSpan.FromMinutes(5));
6670
}
67-
return await factory(entry);
71+
return item;
6872
})!;
6973

7074
/// <summary>
@@ -177,7 +181,7 @@ public static int ElementCount(object? value)
177181
if (value != null)
178182
{
179183
var type = value.GetType();
180-
var cacheKey = $"Lambda-Count-{type.GetUniqueTypeName()}";
184+
var cacheKey = $"{CacheKeyPrefix}-Lambda-Count-{type.GetUniqueTypeName()}";
181185
var invoker = Instance.GetOrCreate(cacheKey, entry =>
182186
{
183187
return LambdaExtensions.CountLambda(type).Compile();
@@ -258,15 +262,19 @@ private static JsonLocalizationOptions GetJsonLocalizationOption()
258262
return null;
259263
}
260264

261-
IEnumerable<LocalizedString>? localizedItems = null;
262265
cultureName ??= CultureInfo.CurrentUICulture.Name;
263-
var key = $"{nameof(GetJsonStringByTypeName)}-{assembly.GetUniqueName()}-{cultureName}";
266+
if (string.IsNullOrEmpty(cultureName))
267+
{
268+
return [];
269+
}
270+
271+
var key = $"{CacheKeyPrefix}-{nameof(GetJsonStringByTypeName)}-{assembly.GetUniqueName()}-{cultureName}";
264272
if (forceLoad)
265273
{
266274
Instance.Cache.Remove(key);
267275
}
268276

269-
localizedItems = Instance.GetOrCreate(key, _ =>
277+
var localizedItems = Instance.GetOrCreate(key, entry =>
270278
{
271279
var sections = option.GetJsonStringFromAssembly(assembly, cultureName);
272280
var items = sections.SelectMany(section => section.GetChildren().Select(kv =>
@@ -345,7 +353,7 @@ public static string GetDisplayName(Type modelType, string fieldName)
345353

346354
public static List<SelectedItem> GetNullableBoolItems(Type modelType, string fieldName)
347355
{
348-
var cacheKey = $"{nameof(GetNullableBoolItems)}-{CultureInfo.CurrentUICulture.Name}-{modelType.GetUniqueTypeName()}-{fieldName}";
356+
var cacheKey = $"{CacheKeyPrefix}-{nameof(GetNullableBoolItems)}-{modelType.GetUniqueTypeName()}-{fieldName}-{CultureInfo.CurrentUICulture.Name}";
349357
return Instance.GetOrCreate(cacheKey, entry =>
350358
{
351359
var items = new List<SelectedItem>();
@@ -475,7 +483,7 @@ public static TResult GetPropertyValue<TModel, TResult>(TModel model, string fie
475483
TResult GetValue()
476484
{
477485
var type = model.GetType();
478-
var cacheKey = ($"Lambda-Get-{type.GetUniqueTypeName()}", typeof(TModel), fieldName, typeof(TResult));
486+
var cacheKey = $"{CacheKeyPrefix}-Lambda-Get-{type.GetUniqueTypeName()}-{typeof(TModel)}-{fieldName}-{typeof(TResult)}";
479487
var invoker = Instance.GetOrCreate(cacheKey, entry =>
480488
{
481489
if (type.Assembly.IsDynamic)
@@ -503,7 +511,7 @@ public static void SetPropertyValue<TModel, TValue>(TModel model, string fieldNa
503511
else
504512
{
505513
var type = model.GetType();
506-
var cacheKey = ($"Lambda-Set-{type.GetUniqueTypeName()}", typeof(TModel), fieldName, typeof(TValue));
514+
var cacheKey = $"{CacheKeyPrefix}-Lambda-Set-{type.GetUniqueTypeName()}-{typeof(TModel)}-{fieldName}-{typeof(TValue)}";
507515
var invoker = Instance.GetOrCreate(cacheKey, entry =>
508516
{
509517
if (type.Assembly.IsDynamic)
@@ -530,7 +538,7 @@ public static void SetPropertyValue<TModel, TValue>(TModel model, string fieldNa
530538
if (model != null)
531539
{
532540
var type = model.GetType();
533-
var cacheKey = ($"Lambda-GetKeyValue-{type.GetUniqueTypeName()}-{customAttribute?.GetUniqueTypeName()}", typeof(TModel));
541+
var cacheKey = $"{CacheKeyPrefix}-Lambda-{nameof(GetKeyValue)}-{type.GetUniqueTypeName()}-{typeof(TModel)}-{customAttribute?.GetUniqueTypeName()}";
534542
var invoker = Instance.GetOrCreate(cacheKey, entry => LambdaExtensions.GetKeyValue<TModel, TValue>(customAttribute).Compile());
535543
ret = invoker(model);
536544
}
@@ -541,21 +549,21 @@ public static void SetPropertyValue<TModel, TValue>(TModel model, string fieldNa
541549
#region Lambda Sort
542550
public static Func<IEnumerable<T>, string, SortOrder, IEnumerable<T>> GetSortFunc<T>()
543551
{
544-
var cacheKey = $"Lambda-{nameof(LambdaExtensions.GetSortLambda)}-{typeof(T).GetUniqueTypeName()}";
552+
var cacheKey = $"{CacheKeyPrefix}-Lambda-{nameof(GetSortFunc)}-{typeof(T).GetUniqueTypeName()}";
545553
return Instance.GetOrCreate(cacheKey, entry => LambdaExtensions.GetSortLambda<T>().Compile());
546554
}
547555

548556
public static Func<IEnumerable<T>, List<string>, IEnumerable<T>> GetSortListFunc<T>()
549557
{
550-
var cacheKey = $"Lambda-{nameof(LambdaExtensions.GetSortListLambda)}-{typeof(T).GetUniqueTypeName()}";
558+
var cacheKey = $"{CacheKeyPrefix}-Lambda-{nameof(GetSortListFunc)}-{typeof(T).GetUniqueTypeName()}";
551559
return Instance.GetOrCreate(cacheKey, entry => LambdaExtensions.GetSortListLambda<T>().Compile());
552560
}
553561
#endregion
554562

555563
#region Lambda ConvertTo
556564
public static Func<object, IEnumerable<string?>> CreateConverterInvoker(Type type)
557565
{
558-
var cacheKey = $"Lambda-{nameof(CreateConverterInvoker)}-{type.GetUniqueTypeName()}";
566+
var cacheKey = $"{CacheKeyPrefix}-Lambda-{nameof(CreateConverterInvoker)}-{type.GetUniqueTypeName()}";
559567
return Instance.GetOrCreate(cacheKey, entry =>
560568
{
561569
var method = typeof(CacheManager)
@@ -583,15 +591,15 @@ public static Func<IEnumerable<T>, List<string>, IEnumerable<T>> GetSortListFunc
583591
/// <returns></returns>
584592
public static Func<TModel, ITableColumn, Func<TModel, ITableColumn, object?, Task>, object> GetOnValueChangedInvoke<TModel>(Type fieldType)
585593
{
586-
var cacheKey = $"Lambda-{nameof(GetOnValueChangedInvoke)}-{typeof(TModel).GetUniqueTypeName()}-{fieldType.GetUniqueTypeName()}";
594+
var cacheKey = $"{CacheKeyPrefix}-Lambda-{nameof(GetOnValueChangedInvoke)}-{typeof(TModel).GetUniqueTypeName()}-{fieldType.GetUniqueTypeName()}";
587595
return Instance.GetOrCreate(cacheKey, entry => Utility.CreateOnValueChanged<TModel>(fieldType).Compile());
588596
}
589597
#endregion
590598

591599
#region Format
592600
public static Func<object, string, IFormatProvider?, string> GetFormatInvoker(Type type)
593601
{
594-
var cacheKey = $"{nameof(GetFormatInvoker)}-{type.GetUniqueTypeName()}";
602+
var cacheKey = $"{CacheKeyPrefix}-Lambda-{nameof(GetFormatInvoker)}-{type.GetUniqueTypeName()}";
595603
return Instance.GetOrCreate(cacheKey, entry => GetFormatLambda(type).Compile());
596604

597605
static Expression<Func<object, string, IFormatProvider?, string>> GetFormatLambda(Type type)
@@ -629,7 +637,7 @@ public static Func<IEnumerable<T>, List<string>, IEnumerable<T>> GetSortListFunc
629637

630638
public static Func<object, IFormatProvider?, string> GetFormatProviderInvoker(Type type)
631639
{
632-
var cacheKey = $"{nameof(GetFormatProviderInvoker)}-{type.GetUniqueTypeName()}";
640+
var cacheKey = $"{CacheKeyPrefix}-Lambda-{nameof(GetFormatProviderInvoker)}-{type.GetUniqueTypeName()}";
633641
return Instance.GetOrCreate(cacheKey, entry => GetFormatProviderLambda(type).Compile());
634642

635643
static Expression<Func<object, IFormatProvider?, string>> GetFormatProviderLambda(Type type)
@@ -656,7 +664,7 @@ public static Func<IEnumerable<T>, List<string>, IEnumerable<T>> GetSortListFunc
656664

657665
public static object GetFormatterInvoker(Type type, Func<object, Task<string?>> formatter)
658666
{
659-
var cacheKey = $"{nameof(GetFormatterInvoker)}-{type.GetUniqueTypeName()}";
667+
var cacheKey = $"{CacheKeyPrefix}-Lambda-{nameof(GetFormatterInvoker)}-{type.GetUniqueTypeName()}";
660668
var invoker = Instance.GetOrCreate(cacheKey, entry => GetFormatterInvokerLambda(type).Compile());
661669
return invoker(formatter);
662670

test/UnitTest/Services/CacheManagerTest.cs

+17
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,23 @@ public async Task GetOrCreateAsync_Ok()
6767
actual = await GetOrCreateAsync(key);
6868
Assert.Equal(1, actual);
6969

70+
await Cache.GetOrCreateAsync("test-GetOrCreateAsync", async entry =>
71+
{
72+
await Task.Delay(1);
73+
entry.Priority = CacheItemPriority.NeverRemove;
74+
return "test";
75+
});
76+
Cache.Clear();
77+
Assert.True(Cache.TryGetValue("test-GetOrCreateAsync", out string? v));
78+
Assert.Equal("test", v);
79+
80+
await Cache.GetOrCreateAsync("test", async entry =>
81+
{
82+
await Task.Delay(1);
83+
entry.AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(1);
84+
return "test";
85+
});
86+
7087
Task<int> GetOrCreateAsync(object key) => Cache.GetOrCreateAsync<int>(key, entry =>
7188
{
7289
val++;

test/UnitTest/Utils/UtilityTest.cs

+5-2
Original file line numberDiff line numberDiff line change
@@ -372,11 +372,14 @@ public void GetJsonStringByTypeName_Ok()
372372
{
373373
// improve code coverage
374374
var option = Context.Services.GetRequiredService<IOptions<JsonLocalizationOptions>>().Value;
375-
Utility.GetJsonStringByTypeName(option, this.GetType().Assembly, "UnitTest.Utils.UtilityTest+Cat", null, true);
375+
Assert.Empty(Utility.GetJsonStringByTypeName(option, this.GetType().Assembly, "UnitTest.Utils.UtilityTest+Cat1", null, true));
376376

377377
// dynamic
378378
var dynamicType = EmitHelper.CreateTypeByName("test_type", new InternalTableColumn[] { new("Name", typeof(string)) });
379-
Utility.GetJsonStringByTypeName(option, dynamicType!.Assembly, "Test");
379+
Assert.Empty(Utility.GetJsonStringByTypeName(option, dynamicType!.Assembly, "Test"));
380+
381+
// empty cultureName
382+
Assert.Empty(Utility.GetJsonStringByTypeName(option, this.GetType().Assembly, "UnitTest.Utils.UtilityTest+Cat1", "", false));
380383
}
381384

382385
[Fact]

0 commit comments

Comments
 (0)