diff --git a/src/BootstrapBlazor.Server/Extensions/ICacheEntryExtensions.cs b/src/BootstrapBlazor.Server/Extensions/ICacheEntryExtensions.cs index c5fca810dd5..736a41d87d2 100644 --- a/src/BootstrapBlazor.Server/Extensions/ICacheEntryExtensions.cs +++ b/src/BootstrapBlazor.Server/Extensions/ICacheEntryExtensions.cs @@ -27,11 +27,13 @@ public static string GetExpiration(this ICacheEntry entry) } else if (entry.SlidingExpiration.HasValue) { - ret = $"Sliding: {entry.GetSlidingLeftTime().TotalSeconds:###}/{entry.SlidingExpiration.Value.TotalSeconds}"; + var ts = entry.GetSlidingLeftTime(); + ret = ts == TimeSpan.Zero ? "Expirated" : $"Sliding: {ts.TotalSeconds:###}/{entry.SlidingExpiration.Value.TotalSeconds}"; } else if (entry.AbsoluteExpiration.HasValue) { - ret = $"Absolute: {entry.AbsoluteExpiration.Value}"; + var ts = entry.GetAbsoluteLeftTime(); + ret = ts == TimeSpan.Zero ? "Expirated" : $"Absolute: {ts.TotalSeconds:###}"; } else if (entry.ExpirationTokens.Count != 0) { @@ -59,4 +61,14 @@ private static TimeSpan GetSlidingLeftTime(this ICacheEntry entry) } return ts; } + + private static TimeSpan GetAbsoluteLeftTime(this ICacheEntry entry) + { + var ts = entry.AbsoluteExpiration!.Value - DateTimeOffset.UtcNow; + if (ts < TimeSpan.Zero) + { + ts = TimeSpan.Zero; + } + return ts; + } } diff --git a/src/BootstrapBlazor/Extensions/ICacheEntryExtensions.cs b/src/BootstrapBlazor/Extensions/ICacheEntryExtensions.cs index 925fefcf6fa..6bde1aaf3ca 100644 --- a/src/BootstrapBlazor/Extensions/ICacheEntryExtensions.cs +++ b/src/BootstrapBlazor/Extensions/ICacheEntryExtensions.cs @@ -40,4 +40,17 @@ public static class ICacheEntryExtensions } private static PropertyInfo? _lastAccessedProperty = null; + + /// + /// Sets default sliding expiration if no expiration is configured + /// + internal static void SetDefaultSlidingExpiration(this ICacheEntry entry, TimeSpan offset) + { + if (entry.SlidingExpiration == null && entry.AbsoluteExpiration == null + && entry.AbsoluteExpirationRelativeToNow == null + && entry.Priority != CacheItemPriority.NeverRemove) + { + entry.SetSlidingExpiration(offset); + } + } } diff --git a/src/BootstrapBlazor/Options/BootstrapBlazorOptions.cs b/src/BootstrapBlazor/Options/BootstrapBlazorOptions.cs index e0a1dabdf06..139868f135e 100644 --- a/src/BootstrapBlazor/Options/BootstrapBlazorOptions.cs +++ b/src/BootstrapBlazor/Options/BootstrapBlazorOptions.cs @@ -91,35 +91,40 @@ public class BootstrapBlazorOptions : IOptions public TableSettings TableSettings { get; set; } = new(); /// - /// 获得/设置 Step 配置实例 + /// 获得/设置 配置实例 /// public StepSettings StepSettings { get; set; } = new(); /// - /// 获得/设置 ConnectionHubOptions 配置 默认不为空 + /// 获得/设置 配置 默认不为空 /// public ConnectionHubOptions ConnectionHubOptions { get; set; } = new(); /// - /// 获得/设置 WebClientOptions 配置 默认不为空 + /// 获得/设置 配置 默认不为空 /// public WebClientOptions WebClientOptions { get; set; } = new(); /// - /// 获得/设置 IpLocatorOptions 配置 默认不为空 + /// 获得/设置 配置 默认不为空 /// public IpLocatorOptions IpLocatorOptions { get; set; } = new(); /// - /// 获得/设置 ScrollOptions 配置 默认不为空 + /// 获得/设置 配置 默认不为空 /// public ScrollOptions ScrollOptions { get; set; } = new(); /// - /// 获得/设置 ContextMenuOptions 配置 默认不为空 + /// 获得/设置 配置 默认不为空 /// public ContextMenuOptions ContextMenuOptions { get; set; } = new(); + /// + /// 获得/设置 CacheManagerOptions 配置 默认不为空 + /// + public CacheManagerOptions CacheManagerOptions { get; set; } = new(); + BootstrapBlazorOptions IOptions.Value => this; /// diff --git a/src/BootstrapBlazor/Options/CacheManagerOptions.cs b/src/BootstrapBlazor/Options/CacheManagerOptions.cs new file mode 100644 index 00000000000..af2a81ff2bd --- /dev/null +++ b/src/BootstrapBlazor/Options/CacheManagerOptions.cs @@ -0,0 +1,27 @@ +// 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 + +namespace BootstrapBlazor.Components; + +/// +/// CacheManagerOptions 配置类 +/// +public class CacheManagerOptions +{ + /// + /// 获得/设置 是否开启 CacheManager 功能 默认 true 开启 + /// + public bool Enable { get; set; } = true; + + /// + /// 获得/设置 滑动缓存过期时间 默认 5 分钟 + /// + public TimeSpan SlidingExpiration { get; set; } = TimeSpan.FromMinutes(5); + + /// + /// 获得/设置 绝对缓存过期时间 默认 10 秒钟 + /// + public TimeSpan AbsoluteExpiration { get; set; } = TimeSpan.FromSeconds(10); +} diff --git a/src/BootstrapBlazor/Services/CacheManager.cs b/src/BootstrapBlazor/Services/CacheManager.cs index 74a03cf0c2b..90eca88ad94 100644 --- a/src/BootstrapBlazor/Services/CacheManager.cs +++ b/src/BootstrapBlazor/Services/CacheManager.cs @@ -30,6 +30,9 @@ internal class CacheManager : ICacheManager [NotNull] private static CacheManager? Instance { get; set; } + [NotNull] + private static BootstrapBlazorOptions? Options { get; set; } + private const string CacheKeyPrefix = "BootstrapBlazor"; /// @@ -42,6 +45,7 @@ public CacheManager(IServiceProvider provider, IMemoryCache memoryCache) Provider = provider; Cache = memoryCache; Instance = this; + Options = Provider.GetRequiredService>().Value; } /// @@ -51,10 +55,7 @@ public TItem GetOrCreate(object key, Func factory) => { var item = factory(entry); - if (entry.SlidingExpiration == null && entry.AbsoluteExpiration == null && entry.Priority != CacheItemPriority.NeverRemove) - { - entry.SetSlidingExpiration(TimeSpan.FromMinutes(5)); - } + entry.SetDefaultSlidingExpiration(Options.CacheManagerOptions.SlidingExpiration); return item; })!; @@ -65,10 +66,7 @@ public Task GetOrCreateAsync(object key, Func(TModel model, string fieldName) { if (type.Assembly.IsDynamic) { - entry.SetAbsoluteExpiration(TimeSpan.FromSeconds(10)); + entry.SetAbsoluteExpiration(Options.CacheManagerOptions.AbsoluteExpiration); } return LambdaExtensions.GetPropertyValueLambda(model, fieldName).Compile(); @@ -557,7 +555,7 @@ public static void SetPropertyValue(TModel model, string fieldNa { if (type.Assembly.IsDynamic) { - entry.SetAbsoluteExpiration(TimeSpan.FromSeconds(10)); + entry.SetAbsoluteExpiration(Options.CacheManagerOptions.AbsoluteExpiration); } return LambdaExtensions.SetPropertyValueLambda(model, fieldName).Compile(); }); diff --git a/test/UnitTest/Options/BootstrapBlazorOptionsTest.cs b/test/UnitTest/Options/BootstrapBlazorOptionsTest.cs index 04a3e5d41b0..81420ae7474 100644 --- a/test/UnitTest/Options/BootstrapBlazorOptionsTest.cs +++ b/test/UnitTest/Options/BootstrapBlazorOptionsTest.cs @@ -103,4 +103,19 @@ public void Options_TableExportOptions() Assert.Equal(",", exportOptions.ArrayDelimiter); } + + [Fact] + public void CacheManagerOptions_Ok() + { + var options = new BootstrapBlazorOptions(); + Assert.NotNull(options.CacheManagerOptions); + + options.CacheManagerOptions.Enable = true; + options.CacheManagerOptions.SlidingExpiration = TimeSpan.FromSeconds(1); + options.CacheManagerOptions.AbsoluteExpiration = TimeSpan.FromSeconds(1); + + Assert.Equal(TimeSpan.FromSeconds(1), options.CacheManagerOptions.AbsoluteExpiration); + Assert.Equal(TimeSpan.FromSeconds(1), options.CacheManagerOptions.SlidingExpiration); + Assert.True(options.CacheManagerOptions.Enable); + } }