来自IMemoryCache的ASP.NET Core清除缓存(由CacheExtensions类的Set方法设置)

时间:2018-03-08 15:04:20

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

首先看来这看起来与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,但这似乎有点过分。有没有更简单的选择?

4 个答案:

答案 0 :(得分:5)

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

在内部,它使用IMemoryCache 用例与另外两个功能完全相同:

  1. 清除内存缓存中的所有项目
  2. 遍历所有键/值对
  3. 你必须注册单身人士:

    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;
        }
    }
    

答案 1 :(得分:3)

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

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

因此,实现此目的的解决方法是存储您自己实现的单例服务中添加的所有键。比如像

那样的smth
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)函数。

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

答案 2 :(得分:0)

逐个密钥布置和移除密钥不是一个好主意,失败点太多。我已经在生产和单元测试中使用了此代码,效果很好。关于IMemoryCache为什么缺少Clear方法,我还没有找到好的答案。如果Compact(0.0)起作用了,那将是一回事,但是它根本不起作用,或者如果它起作用了,那就太懒了。此代码应在.NET Core 2.2上运行:

MusicalInstrument instrument = new MusicalInstrument(1, 12.5, "Guitar");
MusicalInstrument immutableView = ImmutableProxy.create(instrument);

assertThat(immutableView.getName()).isEqualTo("Guitar");

// throws UnsupportedOperationException
immutableView.setName(…);

答案 3 :(得分:0)

在ASP.NET Core中,您可以在services.AddMemoryCache()的{​​{1}}中添加ConfigureServices。进入控制器后,只需使用Startup参数的DI即可:

IMemoryCache

然后,当您要删除或清除缓存时使用

NameController(IMemoryCache memoryCache)

此版本从1.1开始