如何在 asp.net core 中遍历 MemoryCache?
Posted
技术标签:
【中文标题】如何在 asp.net core 中遍历 MemoryCache?【英文标题】:How to iterate through MemoryCache in asp.net core? 【发布时间】:2017-09-26 04:42:36 【问题描述】:IMemoryCache 中没有可用的方法允许遍历每个缓存项。我的项目很小,我不想使用 Redis 之类的其他选项。
namepsace Microsoft.Extensions.Caching.Memory
public static class CacheExtensions
public static object Get(this IMemoryCache cache, object key);
public static TItem Get<TItem>(this IMemoryCache cache, object key);
public static TItem GetOrCreate<TItem>(this IMemoryCache cache, object key, Func<ICacheEntry, TItem> factory);
[AsyncStateMachine(typeof(CacheExtensions.<GetOrCreateAsync>d__9<>))]
public static Task<TItem> GetOrCreateAsync<TItem>(this IMemoryCache cache, object key, Func<ICacheEntry, Task<TItem>> factory);
public static TItem Set<TItem>(this IMemoryCache cache, object key, TItem value);
public static TItem Set<TItem>(this IMemoryCache cache, object key, TItem value, DateTimeOffset absoluteExpiration);
public static TItem Set<TItem>(this IMemoryCache cache, object key, TItem value, TimeSpan absoluteExpirationRelativeToNow);
public static TItem Set<TItem>(this IMemoryCache cache, object key, TItem value, IChangeToken expirationToken);
public static TItem Set<TItem>(this IMemoryCache cache, object key, TItem value, MemoryCacheEntryOptions options);
public static bool TryGetValue<TItem>(this IMemoryCache cache, object key, out TItem value);
https://github.com/aspnet/Caching/blob/dev/src/Microsoft.Extensions.Caching.Memory/MemoryCache.cs
【问题讨论】:
我不认为有这样的功能,你可以做的简单的事情是将内存缓存包装在一个新的类中,该类存储缓存的键(预存储+每个项目集上的新条目)和一种迭代它们的方法,从 MemoryCache 调用 Get 方法。 迭代 MemoryCache 根本不是该类的用例。当然,您可以通过将缓存包装在另一个类中来添加它,但是您必须处理并发访问缓存导致的所有问题。 我想知道你为什么要遍历整个缓存中的所有项目? @Evk 说我有一些带有键模式的缓存项目:“abc.xyz-0”=> 用于单个项目,“abc.xyz”=> 用于所有项目。现在,如果我对项目数据进行更改,例如更改名称...,我想使用正则表达式或其他任何方式删除所有缓存的项目,以确保下一个请求将获得刷新更新的数据。 @Evk 好吧,MVC 5 中的内存缓存,你可以这样写。 System.Runtime.Caching.MemoryCache.Default.Select(p=> p.Key) 我知道 .net 核心一开始很简单。 【参考方案1】:您应该缓存两种类型的项目。
-
您按原样缓存您的属性,
abc.xyz-0
。
第二次缓存主键名下的属性列表,abc.xyz
示例代码:
cache.Set("abc.xyz-name", name, TimeSpan.FromMinutes(30));
cache.Set("abc.xyz-lastname", lastname, TimeSpan.FromMinutes(30));
cache.Set("abc.xyz-birthday", birthday, TimeSpan.FromMinutes(30));
cache.Set("abc.xyz", new List<string> "abc.xyz-name", "abc.xyz-lastname", "abc.xyz-birthday" , TimeSpan.FromMinutes(30));
以及删除时:
var keys = cache.Get<List<string>>("abc.xyz");
foreach(var key in keys)
cache.Remove(key);
cache.remove("abc.xyz");
大多数服务使用IDistributedCache
(在您的情况下,注册时为MemoryDistributedCache
- 它再次注入IMemoryCache
,即MemoryCache
类)。
在分布式缓存中,您无法遍历所有键,因为可能存在数百万个键,如果您可以/将对其进行迭代,这将显着降低缓存服务的性能。
因此,上述解决方案也很友好,可以在您将内存缓存替换为分布式缓存(例如 Redis)的情况下做好准备。
【讨论】:
我想指出,除非实施了某种并发控制,否则这种解决方案不是并发证明的;考虑两个独立的执行流程在同一个存储桶下添加一个新属性——这可能会导致属性被添加到缓存中,但是存储桶错过了它; 我认为简单地用 Redis 缓存替换 MemoryCache 是一个梦想,我不明白他们为什么需要共享接口。对于一个你肯定不想用同步方法来做你的分布式缓存。其次,您需要考虑到您的分布式缓存存在连接问题。 顺便说一句,你的答案的其余部分没有冒犯 - 只是批评 .NET Core 团队没有在 MemoryCache 上公开 Keys 属性。这意味着每个人都必须推出自己的解决方法,包括处理复杂的并发问题。 好吧,将它添加到接口将强制每个实现实现迭代,甚至是不支持它的商店。再加上它对性能不利,您需要在迭代期间锁定键(因为它们可能会在迭代时过期)然后成为应该加速的组件的瓶颈【参考方案2】:对于大型项目,这有点尴尬。我建议您使用包装类 MemoryCacheManager 并将其注册为 Singleton。 https://gist.github.com/vlapenkov/0a66c40221f9c56d12eb0420fb7cef77
使用
_manager.Get("key", ()=>"value") // to set a key,
_manager.GetKeys() // get all keys
_manager.Remove("key") //remove one key
_manager.Clear() //remove all keys
【讨论】:
嗨@Lapenkov,聪明的解决方案!为什么_allKeys
被标记为static
?由于这属于 IMemoryCache - 这不应该具有相同的生命周期吗?
@Lapenkov - 我认为这个解决方案将在单个服务器上运行,因为上面链接的解决方案中提到的“_allKeys”字典将在每台机器上维护 - 或者我可能缺少一些东西。 .以上是关于如何在 asp.net core 中遍历 MemoryCache?的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET Core中的缓存[1]:如何在一个ASP.NET Core应用中使用缓存
如何在 ASP.Net Core 中使用 IHostedService
asp.net core1.x/asp.net core2.0中如何加载多个配置文件