Skip to content

Commit 0d04f6f

Browse files
authored
feat(ICacheEntry): add GetLastAccessed extension method (#5219)
* doc: 更改示例代码 * doc: 增加缓存时长描述 * refactor: 更改 OnGetDisplayText 增加可为空 * refactor: 重构 CacheManager 优化性能 * doc: 更新示例 * refactor: 增加扩展方法 * doc: 更新超时时长列内容 * doc: 实现过期时间实时更新 * refactor: 精简代码 * test: 更新单元测试 * test: 更新单元测试
1 parent f0fd5dc commit 0d04f6f

File tree

11 files changed

+195
-64
lines changed

11 files changed

+195
-64
lines changed

src/BootstrapBlazor.Server/Components/Pages/CacaheExpiration.razor.cs

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,11 @@ namespace BootstrapBlazor.Server.Components.Pages;
1212
/// </summary>
1313
public partial class CacaheExpiration
1414
{
15-
[Inject, NotNull]
16-
private ICacheManager? CacheManager { get; set; }
17-
1815
/// <summary>
19-
/// 获得/设置 <see cref="TableColumnContext{TItem, TValue}"/> 实例
16+
/// 获得/设置 <see cref="ICacheEntry"/> 实例
2017
/// </summary>
2118
[Parameter, NotNull]
22-
public object? Key { get; set; }
19+
public object? Context { get; set; }
2320

2421
private string? ExpirationTime { get; set; }
2522

@@ -39,24 +36,6 @@ private async Task GetCacheEntryExpiration()
3936
ExpirationTime = "loading ...";
4037
await Task.Yield();
4138

42-
if (CacheManager.TryGetCacheEntry(Key, out ICacheEntry? entry))
43-
{
44-
if (entry.Priority == CacheItemPriority.NeverRemove)
45-
{
46-
ExpirationTime = "Never Remove";
47-
}
48-
else if (entry.SlidingExpiration.HasValue)
49-
{
50-
ExpirationTime = $"Sliding: {entry.SlidingExpiration.Value}";
51-
}
52-
else if (entry.AbsoluteExpiration.HasValue)
53-
{
54-
ExpirationTime = $"Absolute: {entry.AbsoluteExpiration.Value}";
55-
}
56-
else if (entry.ExpirationTokens.Count != 0)
57-
{
58-
ExpirationTime = $"Token: {entry.ExpirationTokens.Count}";
59-
}
60-
}
39+
ExpirationTime = Context is ICacheEntry entry ? entry.GetExpiration() : "-";
6140
}
6241
}

src/BootstrapBlazor.Server/Components/Pages/CacheList.razor

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,17 @@
1010
<TableColumns>
1111
<TableTemplateColumn Text="@Localizer["CacheListKey"]" TextWrap="true">
1212
<Template Context="v">
13-
@v.Row.ToString()
13+
@GetKey(v.Row)
1414
</Template>
1515
</TableTemplateColumn>
1616
<TableTemplateColumn Text="@Localizer["CacheListValue"]" TextWrap="true" Width="220">
1717
<Template Context="v">
1818
@GetValue(v.Row)
1919
</Template>
2020
</TableTemplateColumn>
21-
<TableTemplateColumn Text="@Localizer["CacheListExpiration"]" Width="160">
21+
<TableTemplateColumn Text="@Localizer["CacheListExpiration"]" Width="180">
2222
<Template Context="v">
23-
<CacaheExpiration Key="v.Row"></CacaheExpiration>
23+
<CacaheExpiration Context="v.Row"></CacaheExpiration>
2424
</Template>
2525
</TableTemplateColumn>
2626
<TableTemplateColumn Text="@Localizer["CacheListAction"]" Width="80">

src/BootstrapBlazor.Server/Components/Pages/CacheList.razor.cs

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ public partial class CacheList
2424
/// <summary>
2525
/// <inheritdoc/>
2626
/// </summary>
27-
protected override void OnInitialized()
27+
protected override async Task OnParametersSetAsync()
2828
{
29-
base.OnInitialized();
29+
await base.OnParametersSetAsync();
30+
31+
await Task.Yield();
3032
UpdateCacheList();
3133
}
3234

@@ -49,30 +51,29 @@ private void OnRefresh()
4951

5052
private void UpdateCacheList()
5153
{
52-
_cacheList = [.. CacheManager.Keys.OrderBy(i => i.ToString())];
53-
}
54-
55-
private string GetValue(object key)
56-
{
57-
string ret = "-";
58-
if (CacheManager.TryGetValue(key, out object? value))
54+
_cacheList = CacheManager.Keys.OrderBy(i => i.ToString()).Select(key =>
5955
{
60-
if (value is string stringValue)
56+
ICacheEntry? entry = null;
57+
if (CacheManager.TryGetCacheEntry(key, out var val))
6158
{
62-
ret = stringValue;
63-
return ret;
59+
entry = val;
6460
}
61+
return (object)entry!;
62+
}).ToList();
63+
}
6564

66-
if (value is IEnumerable)
67-
{
68-
ret = $"{LambdaExtensions.ElementCount(value)}";
69-
}
70-
else
71-
{
72-
ret = value?.ToString() ?? "-";
73-
}
65+
private static string GetKey(object data) => data is ICacheEntry entry ? entry.Key.ToString()! : "-";
66+
67+
private static string GetValue(object data) => data is ICacheEntry entry ? GetCacheEntryValue(entry) : "-";
68+
69+
private static string GetCacheEntryValue(ICacheEntry entry)
70+
{
71+
var value = entry.Value;
72+
if (value is string stringValue)
73+
{
74+
return stringValue;
7475
}
7576

76-
return ret;
77+
return value is IEnumerable ? $"{LambdaExtensions.ElementCount(value)}" : value?.ToString() ?? "-";
7778
}
7879
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ partial class AutoFills
1818
[NotNull]
1919
private Foo Model3 { get; set; } = new();
2020

21-
private static string OnGetDisplayText(Foo foo) => foo.Name ?? "";
21+
private static string? OnGetDisplayText(Foo? foo) => foo?.Name;
2222

2323
[NotNull]
2424
private IEnumerable<Foo>? Items1 { get; set; }

src/BootstrapBlazor.Server/Components/Samples/InputGroups.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@
8888
<div class="col-12 col-sm-6">
8989
<BootstrapInputGroup>
9090
<BootstrapInputGroupLabel DisplayText="AutoFill" />
91-
<AutoFill Items="AufoFillItems" IsLikeMatch="true" OnGetDisplayText="@(foo => foo.Name)">
91+
<AutoFill Items="AufoFillItems" IsLikeMatch="true" OnGetDisplayText="@(foo => foo?.Name)">
9292
<ItemTemplate>
9393
<div class="d-flex">
9494
<div>

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ protected override void OnInitialized()
5454

5555
private readonly IEnumerable<SelectedItem> Items = new SelectedItem[]
5656
{
57-
new SelectedItem("", "请选择 ..."),
58-
new SelectedItem("Beijing", "北京"),
59-
new SelectedItem("Shanghai", "上海")
57+
new("", "请选择 ..."),
58+
new("Beijing", "北京"),
59+
new("Shanghai", "上海")
6060
};
6161
private string? GroupFormClassString => CssBuilder.Default("row g-3").AddClass("form-inline", FormRowType == RowType.Inline).Build();
6262

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the Apache 2.0 License
3+
// See the LICENSE file in the project root for more information.
4+
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone
5+
6+
using Microsoft.Extensions.Caching.Memory;
7+
using System.Reflection;
8+
9+
namespace BootstrapBlazor.Server.Extensions;
10+
11+
/// <summary>
12+
/// <see cref="ICacheEntry"/> 扩展方法
13+
/// </summary>
14+
public static class ICacheEntryExtensions
15+
{
16+
/// <summary>
17+
/// 获取缓存项过期时间
18+
/// </summary>
19+
/// <param name="entry"></param>
20+
/// <returns></returns>
21+
public static string GetExpiration(this ICacheEntry entry)
22+
{
23+
string? ret;
24+
if (entry.Priority == CacheItemPriority.NeverRemove)
25+
{
26+
ret = "Never Remove";
27+
}
28+
else if (entry.SlidingExpiration.HasValue)
29+
{
30+
ret = $"Sliding: {entry.GetSlidingLeftTime().TotalSeconds:###}/{entry.SlidingExpiration.Value.TotalSeconds}";
31+
}
32+
else if (entry.AbsoluteExpiration.HasValue)
33+
{
34+
ret = $"Absolute: {entry.AbsoluteExpiration.Value}";
35+
}
36+
else if (entry.ExpirationTokens.Count != 0)
37+
{
38+
ret = $"Token: {entry.ExpirationTokens.Count}";
39+
}
40+
else
41+
{
42+
ret = "Not Set";
43+
}
44+
return ret;
45+
}
46+
47+
private static TimeSpan GetSlidingLeftTime(this ICacheEntry entry)
48+
{
49+
var lastAccessed = entry.GetLastAccessed();
50+
return lastAccessed == null ? TimeSpan.Zero : entry.SlidingExpiration!.Value - (DateTime.UtcNow - lastAccessed.Value);
51+
}
52+
}

src/BootstrapBlazor/Components/AutoFill/AutoFill.razor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public partial class AutoFill<TValue>
5858
/// </summary>
5959
[Parameter]
6060
[NotNull]
61-
public Func<TValue, string?>? OnGetDisplayText { get; set; }
61+
public Func<TValue?, string?>? OnGetDisplayText { get; set; }
6262

6363
/// <summary>
6464
/// 图标
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the Apache 2.0 License
3+
// See the LICENSE file in the project root for more information.
4+
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone
5+
6+
using Microsoft.Extensions.Caching.Memory;
7+
using System.Reflection;
8+
9+
namespace BootstrapBlazor.Components;
10+
11+
/// <summary>
12+
/// <see cref="ICacheEntry"/> 扩展方法
13+
/// </summary>
14+
public static class ICacheEntryExtensions
15+
{
16+
/// <summary>
17+
/// 获得缓存项 <see cref="ICacheEntry"/> 最后访问时间
18+
/// </summary>
19+
/// <param name="entry"></param>
20+
/// <param name="force"></param>
21+
/// <returns></returns>
22+
public static DateTime? GetLastAccessed(this ICacheEntry entry, bool force = false)
23+
{
24+
if (force)
25+
{
26+
_lastAccessedProperty = null;
27+
}
28+
_lastAccessedProperty ??= entry.GetType().GetProperty("LastAccessed", BindingFlags.Instance | BindingFlags.NonPublic);
29+
30+
DateTime? ret = null;
31+
if (_lastAccessedProperty != null)
32+
{
33+
var v = _lastAccessedProperty.GetValue(entry);
34+
if (v is DateTime val)
35+
{
36+
ret = val;
37+
}
38+
}
39+
return ret;
40+
}
41+
42+
private static PropertyInfo? _lastAccessedProperty = null;
43+
}

src/BootstrapBlazor/Services/CacheManager.cs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ public IEnumerable<object> Keys
178178

179179
private MethodInfo? _allValuesMethodInfo = null;
180180

181+
private static readonly FieldInfo _coherentStateFieldInfo = typeof(MemoryCache).GetField("_coherentState", BindingFlags.Instance | BindingFlags.NonPublic)!;
182+
183+
private static MethodInfo GetAllValuesMethodInfo(Type type) => type.GetMethod("GetAllValues", BindingFlags.Instance | BindingFlags.Public)!;
184+
181185
/// <summary>
182186
/// <inheritdoc/>
183187
/// </summary>
@@ -200,18 +204,10 @@ public bool TryGetCacheEntry(object? key, [NotNullWhen(true)] out ICacheEntry? e
200204
return entry != null;
201205
}
202206

203-
private static object GetCoherentState(MemoryCache cache)
204-
{
205-
var fieldInfo = cache.GetType().GetField("_coherentState", BindingFlags.Instance | BindingFlags.NonPublic)!;
206-
return fieldInfo.GetValue(cache)!;
207-
}
208-
209-
private static MethodInfo GetAllValuesMethodInfo(object coherentStateInstance) => coherentStateInstance.GetType().GetMethod("GetAllValues", BindingFlags.Instance | BindingFlags.Public)!;
210-
211207
private List<ICacheEntry> GetAllValues(MemoryCache cache)
212208
{
213-
_coherentStateInstance ??= GetCoherentState(cache);
214-
_allValuesMethodInfo ??= GetAllValuesMethodInfo(_coherentStateInstance);
209+
_coherentStateInstance = _coherentStateFieldInfo.GetValue(cache)!;
210+
_allValuesMethodInfo ??= GetAllValuesMethodInfo(_coherentStateInstance.GetType());
215211

216212
var ret = new List<ICacheEntry>();
217213
if (_allValuesMethodInfo.Invoke(_coherentStateInstance, null) is IEnumerable<ICacheEntry> values)

0 commit comments

Comments
 (0)