如何从ASP.NET核心中的IMemoryCache中删除所有对象(重置)

ead*_*dam 21 c# asp.net-core-mvc asp.net-core

我可以找到一种remove方法来IMemoryCache从其键中删除对象.有没有办法重置整个缓存并删除所有对象?

编辑:

如何清除MemoryCache? 链接中提供的Dispose方法在asp.net 5中给出了一个例外.ObjectDisposedException: Cannot access a disposed object. Object name: 'Microsoft.Extensions.Caching.Memory.MemoryCache'.

ale*_*eha 28

https://docs.microsoft.com/en-us/aspnet/core/performance/caching/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();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 您必须非常小心地执行此实现,因为如果您不经常调用 Reset(),则可能会导致严重的内存泄漏。以下是一些示例代码,演示了此类问题的实际情况:https://gist.github.com/tatarincev/4c942a7603a061d41deb393e0aa66545 (7认同)

jjx*_*tra 9

最简单的方法是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);
}
Run Code Online (Sandbox Code Playgroud)


小智 7

为了重置 IMemoryCache 对象,我创建了一个使用 GetType() 中的 GetProperty() 访问 EntriesCollection 属性的方法。有了集合,我使用 GetType() 的 GetMethod() 来调用 Clear() 方法。

保持这样的状态:

public void IMemoryCacheClear(IMemoryCache memoryCache)
{
    PropertyInfo prop = memoryCache.GetType().GetProperty("EntriesCollection", BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.NonPublic | BindingFlags.Public);
    if (prop is null)
        return;
    object innerCache = prop.GetValue(memoryCache);
    MethodInfo clearMethod = innerCache.GetType().GetMethod("Clear", BindingFlags.Instance | BindingFlags.Public);
    clearMethod.Invoke(innerCache, null);
}
Run Code Online (Sandbox Code Playgroud)

目前我迁移到.NET 7,我需要更正该方法,因为 EntriesCollection 不再返回集合数据。从 .NET 7 开始,Clear() 方法现在出现在 MemoryCache 类中。因此,要修复此问题,只需将变量转换为 MemoryCache 并调用 Clear() 方法即可。

修正是这样的:

public void IMemoryCacheClear(IMemoryCache memoryCache)
{
    if (memoryCache is MemoryCache cache)
    {
        cache.Clear();    
    }
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!


b.p*_*ell 2

截至 RC1 的答案是,根据我所读到的和被告知的,你不能开箱即用(我确实在 GitHub 上读到,也许有一种方法可以创建触发器来促进即将到来的这一点)。

目前,您可以获取、设置和删除。我认为你的选择是:

  1. 创建一个缓存管理器包装器来跟踪所有密钥,然后您可以根据需要批量删除这些项目。我不喜欢这个,但它会起作用。当然,如果您不是控制添加的人,则缓存中可能存在您不知道的内容(您可以将您的计数与它的计数进行比较以查看)。如果将 IMemoryCache 转换为 MemoryCache,您可以获得公开的 Count 属性。
  2. 分叉程序集并公开密钥和/或添加方法来删除这些项目。有一个底层字典保存着这些键。我这样做了,编译了它,为其创建了一个 Nuget 包,然后替换了 RC1 版本,只是为了看看我是否可以(并且它有效)。不确定这是否是正确的方法,但这是对我的分叉的提交,我刚刚添加了一个只读属性,我将键转储到对象列表中(键存储为对象)。与过去的 MemoryCache 实现一样,如果您暴露了密钥,它们在转储后可能会过时,但如果您只是使用它们来清除所有内容,那么这应该不重要。

https://github.com/blakepell/Caching/commit/165ae5ec13cc51c44a6007d6b88bd9c567e1d724

我昨晚发布了这个问题,试图弄清楚是否有一个好的方法来专门检查缓存中的内容(询问为什么我们没有办法)。如果你不问,你永远不会知道这是否重要,所以我想为什么不呢。

https://github.com/aspnet/Caching/issues/149