如何在asp.net核心中检索内存缓存键列表?

时间:2017-08-09 17:24:56

标签: c# asp.net-mvc caching asp.net-core

简明扼要。是否可以在.Net Core Web应用程序中列出内存缓存中的所有注册密钥?

我在IMemoryCache界面中找不到任何内容。

8 个答案:

答案 0 :(得分:6)

.Net Core中还没有这样的东西。 这是我的解决方法:

 var field = typeof(MemoryCache).GetProperty("EntriesCollection", BindingFlags.NonPublic | BindingFlags.Instance);
 var collection = field.GetValue(_memoryCache) as ICollection;
 var items = new List<string>();
 if (collection != null)
 foreach (var item in collection)
 {
      var methodInfo = item.GetType().GetProperty("Key");
      var val = methodInfo.GetValue(item);
      items.Add(val.ToString());
 }

答案 1 :(得分:4)

正如其他答案所指出的那样,Microsoft.Extensions.Caching.Memory.MemoryCache的当前实现并未公开任何允许检索所有缓存键的成员,尽管如果使用反射可以解决问题。

此答案建立在MarkM的答案上,它通过将反射的使用量减少到最低来提高解决方案的速度。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.Extensions.Caching.Memory;

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

用法:

var cache = new MemoryCache(new MemoryCacheOptions());
cache.GetOrCreate(1, ce => "one");
cache.GetOrCreate("two", ce => "two");

foreach (var key in cache.GetKeys())
    Console.WriteLine($"Key: '{key}', Key type: '{key.GetType()}'");

foreach (var key in cache.GetKeys<string>())
    Console.WriteLine($"Key: '{key}', Key type: '{key.GetType()}'");

输出:

Key: '1', Key type: 'System.Int32'
Key: 'two', Key type: 'System.String'
Key: 'two', Key type: 'System.String'

注意:

  • 反射使用减少为builds the GetEntriesCollection delegate。当我们使用EntriesCollection的键时,不使用反射。当我们遍历MemoryCache的键的长集合时,这可以节省一些时间和资源。
  • 在解决方案中,我们将EntriesCollection属性投射到IDictionary,尽管其后备字段_entries的类型为ConcurrentDictionary<object, CacheEntry>。我们无法将其直接转换为该类型,因为CacheEntry类型是内部类型。

答案 2 :(得分:2)

目前在IMemoryCache接口中没有这样的方法来返回所有缓存键。根据{{​​3}}评论,我认为将来不会添加。

引用this github issue评论

  

我认为这是可行的,因为部分想法是可行的   缓存就是你提出一个问题后的片刻   答案本可以改变。也就是说,假设你有答案   哪些键存在 - 片刻之后清除缓存和列表   你拥有的钥匙是无效的。

如果您需要密钥,则应在将项目设置为缓存时维护应用程序中的密钥列表,并根据需要使用该密钥。

答案 3 :(得分:1)

我们实现了这个概念,以便通过正则表达式模式进行删除。

完整的实施可以在Saturn72 github repository中找到。 这些天我们正在转向AspNet Core,因此位置可能会发生变化。 在存储库中搜索MemoryCacheManager This is the current location

答案 4 :(得分:1)

MarkM的答案对我而言并不奏效,也无法将结果转换为ICollection,但是我接受了这个想法并提出了对我来说非常有效的方法。希望它也可以帮助其他人:

// Get the empty definition for the EntriesCollection
var cacheEntriesCollectionDefinition = typeof(MemoryCache).GetProperty("EntriesCollection", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);

// Populate the definition with your IMemoryCache instance.  
// It needs to be cast as a dynamic, otherwise you can't
// loop through it due to it being a collection of objects.
var cacheEntriesCollection = cacheEntriesCollectionDefinition.GetValue(instanceIMemoryCache) as dynamic;

// Define a new list we'll be adding the cache entries too
List<Microsoft.Extensions.Caching.Memory.ICacheEntry> cacheCollectionValues = new List<Microsoft.Extensions.Caching.Memory.ICacheEntry>();

foreach (var cacheItem in cacheEntriesCollection)
{
    // Get the "Value" from the key/value pair which contains the cache entry   
    Microsoft.Extensions.Caching.Memory.ICacheEntry cacheItemValue = cacheItem.GetType().GetProperty("Value").GetValue(cacheItem, null);

    // Add the cache entry to the list
    cacheCollectionValues.Add(cacheItemValue);
}

// You can now loop through the cacheCollectionValues list created above however you like.

答案 5 :(得分:0)

您可以在Debugging模式下运行项目,然后在包含Breakpoint的行上设置IMemoryCache,然后检查文件和整个文件。

Cache Entries

答案 6 :(得分:0)

我知道这不是答案,但是... 还有另一种方法,您可以缓存列表。像这样:

public async Task<List<User>> GetUsers()
{
    var cacheKey = "getAllUserCacheKey";

    if (_usersCache != null && ((MemoryCache)_usersCache).Count > 0)
    {
        return _usersCache.Get<List<User>>(cacheKey);
    }

    var users = await _userRepository.GetAll();


    // Set cache options.
    var cacheEntryOptions = new MemoryCacheEntryOptions()
        .SetSlidingExpiration(TimeSpan.FromMinutes(5));

    _usersCache.Set(cacheKey, users);

    return users;

}

答案 7 :(得分:0)

我正在使用MemoryCacheExtensions,建议in roxton’s answer显示以下内容的密钥列表 lazyCache,将MemoryCache包装为MemoryCacheProvider

public static IEnumerable<string> GetKeys(this IAppCache appCache)  
{
    var cacheProvider = appCache.CacheProvider as MemoryCacheProvider;
    if (cacheProvider != null) //may be MockCacheProvider in tests 
    {
    var field = typeof(MemoryCacheProvider).GetField("cache", BindingFlags.NonPublic | BindingFlags.Instance);
    var memoryCache = field.GetValue(cacheProvider) as MemoryCache;
    return memoryCache.GetKeys<string>();
    }
    return new List<string>();
}