读取MemoryCache的内容,包括过期时间

本文关键字:包括 过期 时间 MemoryCache 读取 | 更新日期: 2023-09-27 18:17:31

是否可以提取MemoryCache对象的内容,包括:

  1. 缓存项键
  2. 缓存项值
  3. 缓存项过期时间?

读取MemoryCache的内容,包括过期时间

提取缓存项键和值很容易,并且在Internet上的其他地方有介绍。经过一些研究,似乎一种方法来提取过期时间为每个项目。我们必须使用反射,因为框架不公开MemoryCache的内部对象。

我们首先创建一个类来存储每个缓存项的信息:

    public class MemoryCacheItemInfo
    {
        public string Key { get; private set; }
        public object CacheItemValue { get; private set; }
        public DateTime Created { get; private set; }
        public DateTime LastUpdateUsage { get; private set; }
        public DateTime AbsoluteExpiry { get; private set; }
        public TimeSpan SlidingExpiry { get; private set; }
        public MemoryCacheItemInfo(string key, object cacheItemValue,
            DateTime created, DateTime lastUpdateUsage, DateTime absoluteExpiry,
            TimeSpan slidingExpiry)
        {
            this.Key = key;
            this.CacheItemValue = cacheItemValue;
            this.Created = created;
            this.LastUpdateUsage = lastUpdateUsage;
            this.AbsoluteExpiry = absoluteExpiry;
            this.SlidingExpiry = slidingExpiry;
        }
    }

现在,我们将使用反射访问私有MemoryCache字段:

    public static MemoryCacheItemInfo[] GetCacheItemInfo(this MemoryCache cache)
    {
        BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
        FieldInfo field = typeof (MemoryCache).GetField("_stores", bindFlags);
        object[] cacheStores = (object[]) field.GetValue(cache);
        List<MemoryCacheItemInfo> info = new List<MemoryCacheItemInfo>();
        foreach (object cacheStore in cacheStores)
        {
            Type cacheStoreType = cacheStore.GetType();
            FieldInfo lockField = cacheStoreType.GetField("_entriesLock", bindFlags);
            object lockObj = lockField.GetValue(cacheStore);
            lock (lockObj)
            {
                FieldInfo entriesField = cacheStoreType.GetField("_entries", bindFlags);
                Hashtable entriesCollection = (Hashtable) entriesField.GetValue(cacheStore);
                foreach (DictionaryEntry cacheItemEntry in entriesCollection)
                {
                    Type cacheItemValueType = cacheItemEntry.Value.GetType();
                    string key = (string) cacheItemEntry.Key.GetType().GetProperty("Key", bindFlags).GetValue(cacheItemEntry.Key);
                    PropertyInfo value = cacheItemValueType.GetProperty("Value", bindFlags);
                    PropertyInfo utcCreated = cacheItemValueType.GetProperty("UtcCreated", bindFlags);
                    PropertyInfo utcLastUpdateUsage = cacheItemValueType.GetProperty("UtcLastUpdateUsage", bindFlags);
                    PropertyInfo utcAbsoluteExpiry = cacheItemValueType.GetProperty("UtcAbsExp", bindFlags);
                    PropertyInfo utcSlidingExpiry = cacheItemValueType.GetProperty("SlidingExp", bindFlags);
                    MemoryCacheItemInfo mcii = new MemoryCacheItemInfo(
                        key,
                        value.GetValue(cacheItemEntry.Value),
                        ((DateTime) utcCreated.GetValue(cacheItemEntry.Value)).ToLocalTime(),
                        ((DateTime) utcLastUpdateUsage.GetValue(cacheItemEntry.Value)).ToLocalTime(),
                        ((DateTime) utcAbsoluteExpiry.GetValue(cacheItemEntry.Value)).ToLocalTime(),
                        ((TimeSpan) utcSlidingExpiry.GetValue(cacheItemEntry.Value))
                        );
                    info.Add(mcii);
                }
            }
        }
        return info.ToArray();
    }

这种方法效率不高,不建议用于生产环境。

另外,访问MemoryCache私有字段是不被Microsoft官方支持的。

MemoryCache对象的内部结构可能会在将来发生变化,这会破坏此代码。