.NET 9 Preview 1 中 MemoryCache 的更新
Intro
.NET 9 Preview 1 中为 MemoryCache 添加了一个
Keys
属性,我们可以通过它来获取 memory cache 中的缓存的 key list 了,另外新增了一个带
MemoryCacheEntryOptions
参数的
GetOrCreate(Async)
重载方法
Sample
Keys Sample
新增的 API:
public classMemoryCache
{
public System.Collections.Generic.IEnumerable<object> Keys { get; }
}
来看下使用示例:
Console.WriteLine("MemoryCache keys non-di sample");
var memoryCache = new MemoryCache(new MemoryCacheOptions());
memoryCache.Set("user:1:roles", "user,manager");
memoryCache.Set("user:1:permission", "read,write");
memoryCache.Set("user:2:roles", "user");
memoryCache.Set("user:2:permission", "read");
foreach (var cacheKey in memoryCache.Keys)
{
Console.WriteLine(cacheKey.ToString());
if (cacheKey isstring cacheKeyStr && cacheKeyStr.StartsWith("user:2:"))
{
memoryCache.Remove(cacheKey);
}
}
Console.WriteLine("some keys had been removed");
foreach (var cacheKey in ((MemoryCache)memoryCache).Keys)
{
Console.WriteLine(cacheKey.ToString());
}
这个示例是直接
new
不使用依赖注入的方式,这里模拟了清除用户缓存的一个操作,将用户 2 的缓存删除并打印所有的 cache key
输出结果如下:
再来看一下使用依赖注入的示例,大体上差不多,只是我们需要转换一下类型,因为这个
Keys
是定义在
MemoryCache
类型上,
IMemoryCache
接口并未定义
Console.WriteLine("MemoryCache keys dependency injection sample");
usingvar services = new ServiceCollection()
.AddMemoryCache()
.BuildServiceProvider();
var memoryCache = services.GetRequiredService<IMemoryCache>();
memoryCache.Set("user:1:roles", "user,manager");
memoryCache.Set("user:1:permission", "read,write");
memoryCache.Set("user:2:roles", "user");
memoryCache.Set("user:2:permission", "read");
foreach (var cacheKey in ((MemoryCache)memoryCache).Keys)
{
Console.WriteLine(cacheKey.ToString());
if (cacheKey isstring cacheKeyStr && cacheKeyStr.StartsWith("user:2:"))
{
memoryCache.Remove(cacheKey);
}
}
Console.WriteLine("some keys had been removed");
foreach (var cacheKey in ((MemoryCache)memoryCache).Keys)
{
Console.WriteLine(cacheKey.ToString());
}
输出结果如下:
GetOrCreate(Async)
override
新的 API 定义如下:
namespace Microsoft.Extensions.Caching.Memory {
public static class CacheExtensions {
+ public static TItem? GetOrCreate<TItem>(this IMemoryCache cache, object key, Func<ICacheEntry, TItem> factory, MemoryCacheEntryOptions? createOptions);
+ public static Task<TItem?> GetOrCreateAsync<TItem>(this IMemoryCache cache, object key, Func<ICacheEntry, Task<TItem>> factory, MemoryCacheEntryOptions? createOptions);
}
}
在原来的
GetOrCreate
/
GetOrCreateAsync
方法的基础上增加了
MemoryCacheEntryOptions
参数,这样我们可以在 options 参数设置缓存的过期时间等,我们 factory 方法就能比较简单了
使用示例如下:
Console.WriteLine("MemoryCache keys dependency injection sample");
usingvar services = new ServiceCollection()
.AddMemoryCache()
.BuildServiceProvider();
var memoryCache = services.GetRequiredService<IMemoryCache>();
var key = "user:2:roles";
FetchValue();
Thread.Sleep(1000);
FetchValue();
Thread.Sleep(3000);
FetchValue();
voidFetchValue()
{
memoryCache.GetOrCreate("no-expiration", _ =>
{
Console.WriteLine("fetch value from source for no-expiration key");
return"user";
});
memoryCache.GetOrCreate(key, _ =>
{
Console.WriteLine("fetch value from source");
return"user";
},
new MemoryCacheEntryOptions() { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(3) });
}
这里有两个缓存,用于对比设置和不设置的区别,
no-expiration
没有设置过期时间,另外一个设置了三秒的过期时间,输出结果如下:
可以看到
fetch value from source
出现了两次,第一次调用的时候缓存不存所以从 source 去取走了 factory 的逻辑,最后一次缓存过期了所以再次从 source 拿了一次,而
no-expiration
key 因为没有过期时间,所以只有在第一次取得时候从 source 取,后面都是从缓存获取
这个 API 的实现比较简单,蹭了一个 PR,哈哈
References
https://github.com/dotnet/runtime/issues/36554
https://github.com/dotnet/runtime/pull/94992/files
https://github.com/dotnet/runtime/issues/92101
https://github.com/dotnet/runtime/pull/94335