diff --git a/src/BootstrapBlazor.Server/Extensions/CacheManagerExtensions.cs b/src/BootstrapBlazor.Server/Extensions/CacheManagerExtensions.cs
deleted file mode 100644
index 5d07de3f5..000000000
--- a/src/BootstrapBlazor.Server/Extensions/CacheManagerExtensions.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the Apache 2.0 License
-// See the LICENSE file in the project root for more information.
-// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone
-
-using Microsoft.Extensions.Caching.Memory;
-using System.Globalization;
-
-namespace BootstrapBlazor.Server.Extensions;
-
-///
-/// CacheManager 扩展类
-///
-internal static class CacheManagerExtensions
-{
- ///
- /// 获得 指定代码文件当前文化设置的本地化资源集合
- ///
- ///
- ///
- ///
- ///
- public static IEnumerable GetLocalizedStrings(this ICacheManager cache, string typeName, JsonLocalizationOptions options)
- {
- var key = $"Snippet-{CultureInfo.CurrentUICulture.Name}-{nameof(GetLocalizedStrings)}-{typeName}";
- return cache.GetOrCreate(key, entry =>
- {
- var type = typeName.Replace('\\', '.');
- return Utility.GetJsonStringByTypeName(options, typeof(CodeSnippetService).Assembly, $"BootstrapBlazor.Server.Components.Samples.{type}");
- });
- }
-
- public static Task GetContentFromFileAsync(this ICacheManager cache, string fileName, Func> factory)
- {
- var key = $"Snippet-{CultureInfo.CurrentUICulture.Name}-{nameof(GetContentFromFileAsync)}-{fileName}";
- return cache.GetOrCreateAsync(key, entry => factory(entry));
- }
-}
diff --git a/src/BootstrapBlazor.Server/Services/CodeSnippetService.cs b/src/BootstrapBlazor.Server/Services/CodeSnippetService.cs
index d563d9577..4024bb12d 100644
--- a/src/BootstrapBlazor.Server/Services/CodeSnippetService.cs
+++ b/src/BootstrapBlazor.Server/Services/CodeSnippetService.cs
@@ -4,53 +4,23 @@
// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone
using Microsoft.Extensions.Options;
-using System.Collections.Frozen;
+using System.Globalization;
namespace BootstrapBlazor.Server.Services;
-class CodeSnippetService
+///
+/// 构造方法
+///
+///
+///
+///
+///
+class CodeSnippetService(
+ IHttpClientFactory factory,
+ ICacheManager cacheManager,
+ IOptions options,
+ IOptions localizerOptions)
{
- private IHttpClientFactory Factory { get; set; }
-
- private string ServerUrl { get; set; }
-
- private string SourceCodePath { get; set; }
-
- private FrozenDictionary SourceCodes { get; set; }
-
- private bool IsDevelopment { get; }
-
- private string ContentRootPath { get; }
-
- private ICacheManager CacheManager { get; set; }
-
- private JsonLocalizationOptions LocalizerOptions { get; }
-
- ///
- /// 构造方法
- ///
- ///
- ///
- ///
- ///
- public CodeSnippetService(
- IHttpClientFactory factory,
- ICacheManager cacheManager,
- IOptionsMonitor options,
- IOptionsMonitor localizerOptions)
- {
- LocalizerOptions = localizerOptions.CurrentValue;
-
- CacheManager = cacheManager;
- Factory = factory;
-
- IsDevelopment = options.CurrentValue.IsDevelopment;
- ContentRootPath = options.CurrentValue.ContentRootPath;
- ServerUrl = options.CurrentValue.ServerUrl;
- SourceCodes = options.CurrentValue.SourceCodes;
- SourceCodePath = options.CurrentValue.SourceCodePath;
- }
-
///
/// 获得示例源码方法
///
@@ -63,14 +33,16 @@ class CodeSnippetService
// codeFile = ajax.razor.cs
var segs = codeFile.Split('.');
var key = segs[0];
- var typeName = SourceCodes.TryGetValue(key.ToLowerInvariant(), out var value) ? value : string.Empty;
+ var typeName = options.Value.SourceCodes.TryGetValue(key.ToLowerInvariant(), out var value) ? value : string.Empty;
if (!string.IsNullOrEmpty(typeName))
{
var fileName = codeFile.Replace(key, typeName);
content = await GetFileContentAsync(fileName);
// 源码修正
- CacheManager.GetLocalizedStrings(typeName, LocalizerOptions).ToList().ForEach(l => content = ReplacePayload(content, l));
+ var type = typeName.Replace('\\', '.');
+ Utility.GetJsonStringByTypeName(localizerOptions.Value, typeof(CodeSnippetService).Assembly, $"BootstrapBlazor.Server.Components.Samples.{type}").ToList()
+ .ForEach(l => content = ReplacePayload(content, l));
content = ReplaceSymbols(content);
content = RemoveBlockStatement(content, "@inject IStringLocalizer<");
}
@@ -93,15 +65,20 @@ class CodeSnippetService
string? payload;
if (OperatingSystem.IsBrowser())
{
- var client = Factory.CreateClient();
+ var client = factory.CreateClient();
client.Timeout = TimeSpan.FromSeconds(5);
- client.BaseAddress = new Uri($"{ServerUrl}/api/");
+ client.BaseAddress = new Uri($"{options.Value.ServerUrl}/api/");
payload = await client.GetStringAsync($"Code?fileName=BootstrapBlazor.Server/Components/Samples/{fileName}");
}
else
{
// 读取硬盘文件
- payload = await CacheManager.GetContentFromFileAsync(fileName, _ => ReadFileAsync(fileName));
+ var key = $"{nameof(GetFileContentAsync)}-{fileName}-{CultureInfo.CurrentUICulture.Name}";
+ payload = await cacheManager.GetOrCreateAsync(key, entry =>
+ {
+ entry.SlidingExpiration = TimeSpan.FromMinutes(10);
+ return ReadFileAsync(fileName);
+ });
}
return payload;
}
@@ -109,9 +86,9 @@ class CodeSnippetService
private async Task ReadFileAsync(string fileName)
{
string? payload;
- var file = IsDevelopment
- ? $"{ContentRootPath}\\..\\BootstrapBlazor.Server\\Components\\Samples\\{fileName}"
- : $"{SourceCodePath}BootstrapBlazor.Server\\Components\\Samples\\{fileName}";
+ var file = options.Value.IsDevelopment
+ ? $"{options.Value.ContentRootPath}\\..\\BootstrapBlazor.Server\\Components\\Samples\\{fileName}"
+ : $"{options.Value.SourceCodePath}BootstrapBlazor.Server\\Components\\Samples\\{fileName}";
if (!OperatingSystem.IsWindows())
{
file = file.Replace('\\', '/');
diff --git a/src/BootstrapBlazor/BootstrapBlazor.csproj b/src/BootstrapBlazor/BootstrapBlazor.csproj
index 6c128a84e..426c4720b 100644
--- a/src/BootstrapBlazor/BootstrapBlazor.csproj
+++ b/src/BootstrapBlazor/BootstrapBlazor.csproj
@@ -1,7 +1,7 @@
- 9.2.9-beta01
+ 9.2.9-beta02
diff --git a/src/BootstrapBlazor/Services/CacheManager.cs b/src/BootstrapBlazor/Services/CacheManager.cs
index a250b4f68..67eb3929f 100644
--- a/src/BootstrapBlazor/Services/CacheManager.cs
+++ b/src/BootstrapBlazor/Services/CacheManager.cs
@@ -36,7 +36,6 @@ internal class CacheManager : ICacheManager
///
public CacheManager(IServiceProvider provider, IMemoryCache memoryCache)
{
- // 为了避免依赖导致的报错,构造函数避免使用其他服务
Provider = provider;
Cache = memoryCache;
Instance = this;
@@ -47,11 +46,13 @@ internal class CacheManager : ICacheManager
///
public TItem GetOrCreate(object key, Func factory) => Cache.GetOrCreate(key, entry =>
{
- if (key is not string)
+ var item = factory(entry);
+
+ if (entry.SlidingExpiration == null && entry.AbsoluteExpiration == null && entry.Priority != CacheItemPriority.NeverRemove)
{
entry.SetSlidingExpiration(TimeSpan.FromMinutes(5));
}
- return factory(entry);
+ return item;
})!;
///
@@ -90,6 +91,10 @@ internal class CacheManager : ICacheManager
///
public void Clear(object? key)
{
+ if (key is "BootstrapBlazor_StartTime")
+ {
+ return;
+ }
if (key is not null)
{
Cache.Remove(key);
@@ -97,9 +102,6 @@ internal class CacheManager : ICacheManager
else if (Cache is MemoryCache c)
{
c.Compact(100);
-
- var dtm = GetStartTime();
- SetStartTime(dtm);
}
}
@@ -113,7 +115,11 @@ internal class CacheManager : ICacheManager
///
private void SetStartTime(DateTimeOffset startDateTimeOffset)
{
- GetOrCreate("BootstrapBlazor_StartTime", _ => startDateTimeOffset);
+ GetOrCreate("BootstrapBlazor_StartTime", entry =>
+ {
+ entry.Priority = CacheItemPriority.NeverRemove;
+ return startDateTimeOffset;
+ });
}
///
@@ -470,7 +476,15 @@ internal class CacheManager : ICacheManager
{
var type = model.GetType();
var cacheKey = ($"Lambda-Get-{type.GetUniqueTypeName()}", typeof(TModel), fieldName, typeof(TResult));
- var invoker = Instance.GetOrCreate(cacheKey, entry => LambdaExtensions.GetPropertyValueLambda(model, fieldName).Compile());
+ var invoker = Instance.GetOrCreate(cacheKey, entry =>
+ {
+ if (type.Assembly.IsDynamic)
+ {
+ entry.SetAbsoluteExpiration(TimeSpan.FromSeconds(10));
+ }
+
+ return LambdaExtensions.GetPropertyValueLambda(model, fieldName).Compile();
+ });
return invoker(model);
}
}
@@ -487,15 +501,17 @@ internal class CacheManager : ICacheManager
d.SetValue(fieldName, value);
}
else
- {
- SetValue();
- }
-
- void SetValue()
{
var type = model.GetType();
var cacheKey = ($"Lambda-Set-{type.GetUniqueTypeName()}", typeof(TModel), fieldName, typeof(TValue));
- var invoker = Instance.GetOrCreate(cacheKey, entry => LambdaExtensions.SetPropertyValueLambda(model, fieldName).Compile());
+ var invoker = Instance.GetOrCreate(cacheKey, entry =>
+ {
+ if (type.Assembly.IsDynamic)
+ {
+ entry.SetAbsoluteExpiration(TimeSpan.FromSeconds(10));
+ }
+ return LambdaExtensions.SetPropertyValueLambda(model, fieldName).Compile();
+ });
invoker(model, value);
}
}
diff --git a/test/UnitTest/Services/CacheManagerTest.cs b/test/UnitTest/Services/CacheManagerTest.cs
index f090132b3..798022563 100644
--- a/test/UnitTest/Services/CacheManagerTest.cs
+++ b/test/UnitTest/Services/CacheManagerTest.cs
@@ -3,6 +3,8 @@
// See the LICENSE file in the project root for more information.
// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone
+using Microsoft.Extensions.Caching.Memory;
+
namespace UnitTest.Services;
public class CacheManagerTest : BootstrapBlazorTestBase
@@ -14,19 +16,32 @@ public class CacheManagerTest : BootstrapBlazorTestBase
var v = Cache.GetStartTime();
Assert.Equal(DateTimeOffset.MinValue, v);
- Cache.GetOrCreate("BootstrapBlazor_StartTime", entry =>
- {
- return 10;
- });
- var v1 = Cache.GetStartTime();
- Assert.Equal(DateTimeOffset.MinValue, v);
-
- Cache.Clear("BootstrapBlazor_StartTime");
Cache.SetStartTime();
- Assert.True(DateTime.Now > Cache.GetStartTime());
+ Assert.Equal(1, Cache.Count);
+ Cache.Clear("BootstrapBlazor_StartTime");
+ Assert.Equal(1, Cache.Count);
+ Cache.Clear();
Assert.Equal(1, Cache.Count);
- Assert.Single(Cache.Keys);
+ Assert.NotEqual(DateTimeOffset.MinValue, Cache.GetStartTime());
+ }
+
+ [Fact]
+ public void GetStartTime_Number()
+ {
+ var context = new TestContext();
+ context.Services.AddBootstrapBlazor();
+ var cache = context.Services.GetRequiredService();
+
+ var v = cache.GetOrCreate("BootstrapBlazor_StartTime", entry =>
+ {
+ return 1;
+ });
+ Assert.Equal(1, v);
+
+ var v2 = cache.GetStartTime();
+ Assert.Equal(DateTimeOffset.MinValue, v2);
+ Assert.Empty(Cache.Keys);
}
[Fact]
@@ -90,6 +105,7 @@ public class CacheManagerTest : BootstrapBlazorTestBase
int GetOrCreate(string key) => Cache.GetOrCreate(key, entry =>
{
+ entry.SlidingExpiration = TimeSpan.FromSeconds(1);
val++;
return val;
});
@@ -108,6 +124,7 @@ public class CacheManagerTest : BootstrapBlazorTestBase
int GetOrCreate(string key) => Cache.GetOrCreate(key, entry =>
{
+ entry.AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(1);
val++;
return val;
});