【问题标题】:ASP.NET Core clear cache from IMemoryCache (set by Set method of CacheExtensions class)ASP.NET Core 从 IMemoryCache 清除缓存(由 CacheExtensions 类的 Set 方法设置)
【发布时间】:2018-08-16 23:47:32
【问题描述】:

乍一看,这看起来与 this question 重复,但我不是在问如何清除 EF 的缓存。

如何清除IMemoryCache接口设置的整个缓存?

    public CacheService(IMemoryCache memoryCache) 
    {
        this._memoryCache = memoryCache;
    }

    public async Task<List<string>> GetCacheItem()
    {
        if (!this._memoryCache.TryGetValue("Something", out List<string> list))
        {
            list= await this ...

            this._memoryCache.Set("Something", list, new MemoryCacheEntryOptions().SetPriority(CacheItemPriority.NeverRemove));
        }

        return list;
    }

这只是一个例子。我有许多将值存储到缓存的类/方法。现在我需要将它们全部删除。

在某些情况下,我的密钥是动态创建的,因此我不知道需要删除哪些密钥。清除将是完美的。

我可以编写自己的接口和类,在内部使用IMemoryCache,但这似乎有点过头了。有没有更简单的选择?

【问题讨论】:

  • 你可以向下转换到 MemoryCache 并调用 Clear()。
  • 按照@Tratcher 的建议做,并添加一个针对IMemoryCache 接口的扩展方法。
  • MemoryCache 上没有 clear 函数或扩展方法可以让你清除缓存。因此,实现的套管也无济于事。

标签: asp.net-core .net-core


【解决方案1】:

因为我找不到任何好的解决方案,所以我自己编写。
在 SamiAl90 解决方案(答案)中,我错过了来自 ICacheEntry 接口的所有属性。

在内部它使用IMemoryCache
用例与 2 个附加功能完全相同:

  1. 从内存缓存中清除所有项目
  2. 遍历所有键/值对

你必须注册单例:

serviceCollection.AddSingleton<IMyCache, MyMemoryCache>();

用例:

public MyController(IMyCache cache)
{
    this._cache = cache;
}

[HttpPut]
public IActionResult ClearCache()
{
    this._cache.Clear();
    return new JsonResult(true);
}

[HttpGet]
public IActionResult ListCache()
{
    var result = this._cache.Select(t => new
    {
        Key = t.Key,
        Value = t.Value
    }).ToArray();
    return new JsonResult(result);
}

来源:

public interface IMyCache : IEnumerable<KeyValuePair<object, object>>, IMemoryCache
{
    /// <summary>
    /// Clears all cache entries.
    /// </summary>
    void Clear();
}

public class MyMemoryCache : IMyCache
{
    private readonly IMemoryCache _memoryCache;
    private readonly ConcurrentDictionary<object, ICacheEntry> _cacheEntries = new ConcurrentDictionary<object, ICacheEntry>();

    public MyMemoryCache(IMemoryCache memoryCache)
    {
        this._memoryCache = memoryCache;
    }

    public void Dispose()
    {
        this._memoryCache.Dispose();
    }

    private void PostEvictionCallback(object key, object value, EvictionReason reason, object state)
    {
        if (reason != EvictionReason.Replaced)
            this._cacheEntries.TryRemove(key, out var _);
    }

    /// <inheritdoc cref="IMemoryCache.TryGetValue"/>
    public bool TryGetValue(object key, out object value)
    {
        return this._memoryCache.TryGetValue(key, out value);
    }

    /// <summary>
    /// Create or overwrite an entry in the cache and add key to Dictionary.
    /// </summary>
    /// <param name="key">An object identifying the entry.</param>
    /// <returns>The newly created <see cref="T:Microsoft.Extensions.Caching.Memory.ICacheEntry" /> instance.</returns>
    public ICacheEntry CreateEntry(object key)
    {
        var entry = this._memoryCache.CreateEntry(key);
        entry.RegisterPostEvictionCallback(this.PostEvictionCallback);
        this._cacheEntries.AddOrUpdate(key, entry, (o, cacheEntry) =>
        {
            cacheEntry.Value = entry;
            return cacheEntry;
        });
        return entry;
    }

    /// <inheritdoc cref="IMemoryCache.Remove"/>
    public void Remove(object key)
    {
        this._memoryCache.Remove(key);
    }

    /// <inheritdoc cref="IMyCache.Clear"/>
    public void Clear()
    {
        foreach (var cacheEntry in this._cacheEntries.Keys.ToList())
            this._memoryCache.Remove(cacheEntry);
    }

    public IEnumerator<KeyValuePair<object, object>> GetEnumerator()
    {
        return this._cacheEntries.Select(pair => new KeyValuePair<object, object>(pair.Key, pair.Value.Value)).GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }

    /// <summary>
    /// Gets keys of all items in MemoryCache.
    /// </summary>
    public IEnumerator<object> Keys => this._cacheEntries.Keys.GetEnumerator();
}

public static class MyMemoryCacheExtensions
{
    public static T Set<T>(this IMyCache cache, object key, T value)
    {
        var entry = cache.CreateEntry(key);
        entry.Value = value;
        entry.Dispose();

        return value;
    }

    public static T Set<T>(this IMyCache cache, object key, T value, CacheItemPriority priority)
    {
        var entry = cache.CreateEntry(key);
        entry.Priority = priority;
        entry.Value = value;
        entry.Dispose();

        return value;
    }

    public static T Set<T>(this IMyCache cache, object key, T value, DateTimeOffset absoluteExpiration)
    {
        var entry = cache.CreateEntry(key);
        entry.AbsoluteExpiration = absoluteExpiration;
        entry.Value = value;
        entry.Dispose();

        return value;
    }

    public static T Set<T>(this IMyCache cache, object key, T value, TimeSpan absoluteExpirationRelativeToNow)
    {
        var entry = cache.CreateEntry(key);
        entry.AbsoluteExpirationRelativeToNow = absoluteExpirationRelativeToNow;
        entry.Value = value;
        entry.Dispose();

        return value;
    }

    public static T Set<T>(this IMyCache cache, object key, T value, MemoryCacheEntryOptions options)
    {
        using (var entry = cache.CreateEntry(key))
        {
            if (options != null)
                entry.SetOptions(options);

            entry.Value = value;
        }

        return value;
    }

    public static TItem GetOrCreate<TItem>(this IMyCache cache, object key, Func<ICacheEntry, TItem> factory)
    {
        if (!cache.TryGetValue(key, out var result))
        {
            var entry = cache.CreateEntry(key);
            result = factory(entry);
            entry.SetValue(result);
            entry.Dispose();
        }

        return (TItem)result;
    }

    public static async Task<TItem> GetOrCreateAsync<TItem>(this IMyCache cache, object key, Func<ICacheEntry, Task<TItem>> factory)
    {
        if (!cache.TryGetValue(key, out object result))
        {
            var entry = cache.CreateEntry(key);
            result = await factory(entry);
            entry.SetValue(result);
            entry.Dispose();
        }

        return (TItem)result;
    }
}

【讨论】:

  • 嘿,你能用它来清除使用 标签助手创建的缓存项吗?如果是这样,怎么做?谢谢
  • 对不起,我不知道&lt;cache&gt;标签助手是什么。
【解决方案2】:

逐个删除和删除不是一个好主意,故障点太多。我已经在生产和单元测试中使用了这段代码,它运行良好。关于为什么 IMemoryCache 缺少 Clear 方法,我还没有找到一个好的答案。如果你有 Compact 方法,你可以传递 1.0,即 Compact(1.0) 来清除,但如果没有,这段代码应该可以在 .NET core 2.2 上运行:

PropertyInfo prop = cache.GetType().GetProperty("EntriesCollection", BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.NonPublic | BindingFlags.Public);
object innerCache = prop.GetValue(cache);
MethodInfo clearMethod = innerCache.GetType().GetMethod("Clear", BindingFlags.Instance | BindingFlags.Public);
clearMethod.Invoke(innerCache, null);

【讨论】:

  • 答案对我有用。我调用了 _cache.Compact(1) 并重置了缓存
  • 帮我从 CacheTagHelperMemoryCacheFactory.cache 清除 CacheTagHelper 缓存
【解决方案3】:

这是不可能的。我在 github 上查找了代码,因为我最初的想法是简单地处理它,即使它很脏。 Caching-Middleware 将IMemoryCache 的单个实现注册为单例。

当你对它调用一次 dispose 时,你会再次can not access the cache functions,直到你重新启动整个服务。

因此,实现此目的的解决方法是存储已添加到您自己实现的单例服务中的所有密钥。比如smth like

public class MemoryCacheKeyStore : IMemoryCacheKeyStore, IDisposeable
{
   private readonly List<object> Keys = new List<object>();

   public void AddKey(object key) ...

   public object[] GetKeys() ....

   public void Dispose()
   {
      this.Keys.Clear();
      GC.SuppressFinalize(this);
   }
}

这样你就可以在某个时候访问所有键,遍历它们并调用缓存中的Remove(object key) 函数。

肮脏的解决方法,可能会引起一些麻烦,但据我所知,这是在不重新启动服务的情况下一次删除所有项目的唯一方法:)

【讨论】:

    【解决方案4】:

    在 ASP.NET Core 中,您可以在 ConfigureServicesStartup 中添加 services.AddMemoryCache()。进入控制器后,只需像这样使用IMemoryCache 参数的DI:

    NameController(IMemoryCache memoryCache)
    

    然后,当你想删除或清除缓存时使用

    memoryCache.Remove(yourkeycache)
    

    这适用于 1.1

    【讨论】:

    • 这并没有解决作者的问题:My keys are, in some cases, created dynamically, so I don't know which keys I need to remove.
    猜你喜欢
    • 2017-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-06
    • 2020-03-17
    • 2020-05-29
    • 2011-10-19
    相关资源
    最近更新 更多