[英]How to remove all objects (reset ) from IMemoryCache in ASP.NET core
我可以找到一个remove
方法,通过它的键从IMemoryCache
中删除一个对象。 有没有办法重置整个缓存并删除所有对象?
编辑:
如何清除内存缓存? 链接中提供的 Dispose 方法在 asp.net 5 中给了我一个异常。 ObjectDisposedException: Cannot access a disposed object. Object name: 'Microsoft.Extensions.Caching.Memory.MemoryCache'.
ObjectDisposedException: Cannot access a disposed object. Object name: 'Microsoft.Extensions.Caching.Memory.MemoryCache'.
请参阅ASP.NET Core 中的 Cache in-memory ,特别是有关缓存依赖项的部分。
使用 CancellationTokenSource 允许将多个缓存条目作为一个组逐出
这段代码对我有用:
public class CacheProvider
{
private static CancellationTokenSource _resetCacheToken = new CancellationTokenSource();
private readonly IMemoryCache _innerCache;
/* other methods and constructor removed for brevity */
public T Set<T>(object key, T value)
{
/* some other code removed for brevity */
var options = new MemoryCacheEntryOptions().SetPriority(CacheItemPriority.Normal).SetAbsoluteExpiration(typeExpiration);
options.AddExpirationToken(new CancellationChangeToken(_resetCacheToken.Token));
_innerCache.Set(CreateKey(type, key), value, options);
return value;
}
public void Reset()
{
if (_resetCacheToken != null && !_resetCacheToken.IsCancellationRequested && _resetCacheToken.Token.CanBeCanceled)
{
_resetCacheToken.Cancel();
_resetCacheToken.Dispose();
}
_resetCacheToken = new CancellationTokenSource();
}
}
如果可用,最简单的方法是Compact(1.0)
。 此代码将使用扩展方法清除内存缓存(在单元测试和 .NET 核心 2.2 和 3.1 上的生产中测试)。 如果Compact
不可用,则使用回退方法,从公共Clear
方法开始,然后是内部Clear
方法。 如果这些都不可用,则抛出异常。
/// <summary>
/// Clear IMemoryCache
/// </summary>
/// <param name="cache">Cache</param>
/// <exception cref="InvalidOperationException">Unable to clear memory cache</exception>
/// <exception cref="ArgumentNullException">Cache is null</exception>
public static void Clear(this IMemoryCache cache)
{
if (cache == null)
{
throw new ArgumentNullException("Memory cache must not be null");
}
else if (cache is MemoryCache memCache)
{
memCache.Compact(1.0);
return;
}
else
{
MethodInfo clearMethod = cache.GetType().GetMethod("Clear", BindingFlags.Instance | BindingFlags.Public);
if (clearMethod != null)
{
clearMethod.Invoke(cache, null);
return;
}
else
{
PropertyInfo prop = cache.GetType().GetProperty("EntriesCollection", BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.NonPublic | BindingFlags.Public);
if (prop != null)
{
object innerCache = prop.GetValue(cache);
if (innerCache != null)
{
clearMethod = innerCache.GetType().GetMethod("Clear", BindingFlags.Instance | BindingFlags.Public);
if (clearMethod != null)
{
clearMethod.Invoke(innerCache, null);
return;
}
}
}
}
}
throw new InvalidOperationException("Unable to clear memory cache instance of type " + cache.GetType().FullName);
}
如果您使用标准 MemoryCache,此代码会有所帮助。 文档: https : //docs.microsoft.com/en-us/aspnet/core/performance/caching/memory?view=aspnetcore-3.1#memorycachecompact
_cache.Compact(1.0);
我的解决方案是创建一个包装器,它重新公开现有的几个方法,并通过用全新的对象替换 MemoryCache 对象来添加缺少的方法。 对我来说工作得很好。 代码如下:
public interface IMyMemoryCache : IMemoryCache
{
void Reset();
}
public class MyMemoryCache: IMyMemoryCache
{
IMemoryCache _memoryCache;
public MyMemoryCache()
{
Reset();
}
public void Dispose()
{
_memoryCache.Dispose();
}
public bool TryGetValue(object key, out object value)
{
return _memoryCache.TryGetValue(key, out value);
}
public ICacheEntry CreateEntry(object key)
{
return _memoryCache.CreateEntry(key);
}
public void Remove(object key)
{
_memoryCache.Remove(key);
}
public void Reset()
{
var existingCache = _memoryCache;
_memoryCache = new MemoryCache(new MemoryCacheOptions());
// Dispose existing cache (we override) in 10 minutes
if (existingCache != null)
{
System.Threading.Tasks.Task.Delay(TimeSpan.FromMinutes(10))
.ContinueWith(t =>
{
existingCache.Dispose();
});
}
}
}
RC1 的答案是,您无法根据我所阅读和被告知的内容开箱即用(我确实在 GitHub 上读到过,可能有一种方法可以创建触发器来促进即将到来的这一点)。
目前,为您提供了获取、设置和删除。 我认为您的选择是:
https://github.com/blakepell/Caching/commit/165ae5ec13cc51c44a6007d6b88bd9c567e1d724
我昨晚发布了这个问题,试图找出是否有一种专门检查缓存中内容的好方法(问为什么我们没有办法)。 如果你不问,你永远不会知道这是否重要,所以我想为什么不。
我的解决方案是将缓存中所有项目的新到期日期设置为 1 毫秒。 然后它们过期,因此缓存刷新。
我通过在 IMemoryCache 周围创建一个 FlushableMemoryCache 单例来解决它,它跟踪当前存储在缓存中的键,然后可以迭代它们以将它们全部刷新:
public interface IFlushableMemoryCache
{
void Set<T>(string cacheId, object key, T value);
bool TryGetValue<T>(object key, out T value);
void Remove(string cacheId, object key);
void Flush(string cacheId);
}
public class FlushableMemoryCache : IFlushableMemoryCache
{
private readonly IMemoryCache _memoryCache;
private readonly IDictionary<string, HashSet<object>> _keyDictionary;
public FlushableMemoryCache(IMemoryCache memoryCache)
{
_memoryCache = memoryCache;
_keyDictionary = new Dictionary<string, HashSet<object>>();
}
public void Set<T>(string cacheId, object key, T value)
{
_memoryCache.Set(key, value);
if (_keyDictionary.ContainsKey(cacheId))
{
if (!_keyDictionary[cacheId].Contains(key))
{
_keyDictionary[cacheId].Add(key);
}
}
else
{
_keyDictionary.Add(cacheId, new HashSet<object>(new[] { key }));
}
}
public bool TryGetValue<T>(object key, out T value)
{
return _memoryCache.TryGetValue(key, out value);
}
public void Remove(string cacheId, object key)
{
_memoryCache.Remove(key);
if (_keyDictionary.ContainsKey(cacheId) && _keyDictionary[cacheId].Contains(key))
{
_keyDictionary[cacheId].Remove(key);
}
}
public void Flush(string cacheId)
{
foreach (var key in _keyDictionary[cacheId])
{
_memoryCache.Remove(key);
}
_keyDictionary[cacheId] = new HashSet<object>();
}
}
使用此功能的服务将需要提供该服务独有的cacheId
。 这允许Flush
只清除与特定服务相关的键,而不是缓存中的所有内容!
IMemoryCache _MemoryCache;
public CacheManager(IMemoryCache MemoryCache)
{
_MemoryCache = MemoryCache;
}
public void Clear()
{
_MemoryCache.Dispose();
_MemoryCache = new MemoryCache(new MemoryCacheOptions());
}
不要使用紧凑型解决方案 - 它只是不起作用。
我在整个项目中都使用 IMemoryCache。 在特定时间,我有 42k 个条目。 调用 Compact(1.0) 后,还剩下 14k。
这里似乎描述了唯一的工作方式: How to retrieve a list of Memory Cache keys in asp.net core?
适应了这个问题,我最终使用它如下:
public static class MemoryCacheExtensions
{
private static readonly Func<MemoryCache, object> GetEntriesCollection = Delegate.CreateDelegate(
typeof(Func<MemoryCache, object>),
typeof(MemoryCache).GetProperty("EntriesCollection", BindingFlags.NonPublic | BindingFlags.Instance).GetGetMethod(true),
throwOnBindFailure: true) as Func<MemoryCache, object>;
public static IEnumerable GetKeys(this IMemoryCache memoryCache) =>
((IDictionary)GetEntriesCollection((MemoryCache)memoryCache)).Keys;
public static IEnumerable<T> GetKeys<T>(this IMemoryCache memoryCache) =>
GetKeys(memoryCache).OfType<T>();
public static void Clear(this IMemoryCache memoryCache) => ((IDictionary)GetEntriesCollection((MemoryCache)memoryCache)).Clear();
}
不要忘记投票链接的答案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.