C# MemoryCache避免在关机时刷新

C# MemoryCache避免在关机时刷新,c#,code-cleanup,application-shutdown,C#,Code Cleanup,Application Shutdown,我在web服务集成层中使用System.Runtime.MemoryCache来保存一些外部的、检索速度较慢的产品列表。但是,我想在它们过期时刷新它们,让我的呼叫者不再等待它。因此,我正在使用IIS7.5预热此缓存,并使用RemovedCallback在过期时重新加载数据 但是,当web池进程正常终止时会发生什么?MemoryCache是一次性的,因此它会将我的对象踢出,在这一点上,我将尝试重新填充一个新实例,同时暂停整个过程。我有没有办法安全地检测到我不应该重新加载数据 internal cl

我在web服务集成层中使用
System.Runtime.MemoryCache
来保存一些外部的、检索速度较慢的产品列表。但是,我想在它们过期时刷新它们,让我的呼叫者不再等待它。因此,我正在使用IIS7.5预热此缓存,并使用
RemovedCallback
在过期时重新加载数据

但是,当web池进程正常终止时会发生什么?MemoryCache是一次性的,因此它会将我的对象踢出,在这一点上,我将尝试重新填充一个新实例,同时暂停整个过程。我有没有办法安全地检测到我不应该重新加载数据

internal class ProductCache {
    private static object _lock = new object();
    private static string _cid = Guid.NewGuid().ToString();

    public static Product[] data 
    {
        get
        {
            lock (_lock)
            {
                if (!MemoryCache.Default.Contains(_cid))
                {
                    Product[] p;
                    try
                    {
                        // load data into p
                    }
                    catch (System.Exception e)
                    {
                        Helper.SafeSendExceptionEmail("Integrator.Caching", e);
                        throw e;
                    }
                    MemoryCache.Default.Add(_cid, p, new CacheItemPolicy()
                    {
                        AbsoluteExpiration = DateTimeOffset.Now.AddHours(8),
                        RemovedCallback = arg =>
                        {
                            // query again to force reload
                            var d = data;
                        }
                    });
                }
                return (Product[])MemoryCache.Default[_cid];
            }
        }
    }
}

好的,通过深入查看
MemoryCache
MemoryCacheStore
源代码,缓存似乎在域卸载时自动释放,此时它会释放其所有存储,这反过来会删除缓存项,原因是
cacheSpecificExecution
。这个原因没有在其他地方使用,所以它必须代表“我要死了”的原因(不过在文档中可能会更清楚)


RemovedCallback
获取具有
RemovedReason
CacheEntryRemovedArguments
实例。我假设(但尚未验证)这只是
RemovedReason.Expired
当条目实际过期时。如果内存受到限制等,它也可以被逐出。我在列表中没有看到“我正在关机,所以我将你踢出”的原因。有一个模糊的原因(
cacheSpecificExecution=4,//某个缓存项被逐出的原因是由特定缓存定义的),但这似乎太模糊了……但您只想在该项过期时重新加载,对吗?您不需要知道缓存是否正在关闭,只要您的条目因过期而被删除即可。如果由于任何其他原因删除了它,您都不想重新加载它(想象一下,如果缓存由于内存压力而试图删除条目,而您又将它们扔回缓存,那么会出现混乱!)最坏的情况实际上是严重的——不仅内存不足,而且应用程序还消耗了100%的CPU,除了循环项目外,什么都不做。如果让数据驻留在内存中非常关键,那么您可能首先不需要一个尽力而为的缓存——编写自己的类来保持信息驻留,然后定期重新加载它。这样你就不会试图把一个方形的钉子塞进一个圆形的洞里。我想说的是:缓存应该会加快速度,但如果它被完全移除,则不会影响功能的正确性。因此,只有在已知条目已过期时才重新插入条目,而不是出于任何其他删除原因(如有人显式调用
Remove
)的保守实现应该是完全合法的。如果您正在“挖掘源代码”以获得确切的实现细节,那么您已经非常依赖于特定的行为,而不是任何理智的理由。因此,我建议编写一个完全满足您需要的类。
    public void Dispose()
    {
        if (Interlocked.Exchange(ref this._disposed, 1) == 0)
        {
            this._expires.EnableExpirationTimer(false);
            ArrayList list = new ArrayList(this._entries.Count);
            lock (this._entriesLock)
            {
                foreach (DictionaryEntry entry in this._entries)
                {
                    MemoryCacheEntry entry2 = entry.Value as MemoryCacheEntry;
                    list.Add(entry2);
                }
                foreach (MemoryCacheEntry entry3 in list)
                {
                    MemoryCacheKey key = entry3;
                    entry3.State = EntryState.RemovingFromCache;
                    this._entries.Remove(key);
                }
            }
            foreach (MemoryCacheEntry entry4 in list)
            {
                this.RemoveFromCache(entry4, CacheEntryRemovedReason.CacheSpecificEviction, false);
            }
            this._insertBlock.Close();
        }
    }