【问题标题】:How to prevent HttpRuntime.Cache to remove items in ASP.NET 4.5?如何防止 HttpRuntime.Cache 删除 ASP.NET 4.5 中的项目?
【发布时间】:2017-09-01 08:08:15
【问题描述】:

这是this question 的后续内容,其中包含相互矛盾的答案。我也对与更新版本的 ASP.NET 相关的答案感兴趣。

我的应用程序使用HttpRuntime.Cache 来缓存一些永不过期的模型列表。它们在应用程序预热时加载,很少更改,但经常读取。

我的代码如下:

private void ReportRemovedCallback(string key, object value, CacheItemRemovedReason reason)
{
    if (!ApplicationPoolService.IsShuttingDown())
    {
        var str = $"Removed cached item with key {key} and count {(value as IDictionary)?.Count}, reason {reason}";
        LoggingService.Log(LogLevel.Info, str);
    }
}

private IDictionary<int, T> ThreadSafeCacheAccessAction(Action<IDictionary<int, T>, bool> action = null)
{
    // refresh cache if necessary
    var dict = HttpRuntime.Cache[CacheDictKey] as IDictionary<int, T>;
    bool invalidated = false;
    if (dict == null)
    {
        lock (CacheLockObject)
        {
            // getting expiration times from model attribute
            var cacheInfo = typeof(T).GetCustomAttributes(typeof(UseInCachedRepositoryAttribute), inherit: true).FirstOrDefault() as UseInCachedRepositoryAttribute;
            int absoluteExpiration = cacheInfo?.AbsoluteExpiration ?? Constants.Cache.IndefiniteRetention;
            int slidingExpiration = cacheInfo?.SlidingExpiration ?? Constants.Cache.NoSlidingExpiration;

            dict = _modelRepository.AllNoTracking.ToList().Where(item => item.PkId != 0).ToDictionary(item => item.PkId, item => item);
            HttpRuntime.Cache.Insert(CacheDictKey, dict, dependencies: null,
                absoluteExpiration: DateTime.Now.AddMinutes(absoluteExpiration),
                slidingExpiration: slidingExpiration <= 0 ? Cache.NoSlidingExpiration : TimeSpan.FromMinutes(slidingExpiration),
                priority: CacheItemPriority.NotRemovable,
                onRemoveCallback: ReportRemovedCallback);

            invalidated = true;
        }
    }

根据here 提供的文档,我还在 web.config 中包含了以下标记:

<caching>
  <cache disableExpiration="true" disableMemoryCollection="true" />
</caching>

但是,有时会调用ReportRemovedCallback 来移除项目。我的感觉是 web.config 中的缓存配置被忽略了(文档明确指出它已过时),CacheItemPriority.NotRemovable 仅表示“非常高的优先级”,而不是“永不删除”。

问题: 有没有办法说服 HttpRuntime.Cache 永远不要删除某些项目?或者我应该考虑另一种缓存机制吗?

【问题讨论】:

  • 我总是使用好的和旧的静态变量,它在 AppDomain 的生命周期内保留(例如,直到池回收)。如果由于某种原因您不能使用静态变量,请在您链接的问题中查找@user134706 答案,也许您可​​以了解您的案例发生了什么。
  • @Alisson - 我认为没有理由不使用静态变量。我已经将所有涉及HttpRuntime.Cache 的操作嵌入到一个关键部分中,因此替换应该很容易执行。感谢您的提示。

标签: asp.net asp.net-mvc caching httpruntime.cache cache-expiration


【解决方案1】:

好的,所以我已经挖掘了更多并且没有明确的答案,但是this old docs 的以下配置似乎适用于拒绝过期的试验:

以下默认缓存元素未在 机器配置文件或根 Web.config 文件中,但 .NET 中应用程序返回的默认配置 框架版本 2.0。

<cache disableMemoryCollection="false" 
  disableExpiration="false" privateBytesLimit="0" 
  percentagePhysicalMemoryUsedLimit="90" 
  privateBytesPollTime="00:02:00" /> 

因此,如果物理内存使用率高于 90%,它将驱逐缓存项。由于操作系统倾向于将几乎所有物理内存用于系统缓存(由任务管理器报告),因此这并非听起来那么不可能。

另类

我试了一下MemoryCache,因为它与HttpRuntime.Cache 非常相似。它提供了类似的功能,但缺少 CacheEntryUpdateCallback(您可以提供它,但如果它与 null 不同,则会报 InvalidArgumentException)。

现在我的代码如下:

var dict = MemoryCache.Default.Get(CacheDictKey) as IDictionary<int, T>;

if (dict == null)
{
    lock (CacheLockObject)
    {
        // getting expiration times from model attribute
        var cacheInfo = typeof(T).GetCustomAttributes(typeof(UseInCachedRepositoryAttribute), inherit: true).FirstOrDefault() as UseInCachedRepositoryAttribute;
        int absoluteExpiration = cacheInfo?.AbsoluteExpiration ?? Constants.Cache.IndefiniteRetention;
        int slidingExpiration = cacheInfo?.SlidingExpiration ?? Constants.Cache.NoSlidingExpiration;
         
        dict = _modelRepository.AllNoTracking.ToList().Where(item => item.PkId != 0).ToDictionary(item => item.PkId, item => item);

        var cacheItemPolicy = new CacheItemPolicy
        {
            AbsoluteExpiration = DateTime.Now.AddMinutes(absoluteExpiration),
            SlidingExpiration = slidingExpiration <= 0 ? Cache.NoSlidingExpiration : TimeSpan.FromMinutes(slidingExpiration),
            Priority = System.Runtime.Caching.CacheItemPriority.NotRemovable,
            // throws InvalidArgumentException
            // UpdateCallback = CacheEntryUpdateCallback
        };
        MemoryCache.Default.Add(CacheDictKey, dict, cacheItemPolicy);
    }
}

经过一些测试,没有额外的删除,w3wp.exe 的内存消耗按预期增加。

this answer 中提供了更多详细信息。

【讨论】:

    猜你喜欢
    • 2010-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-23
    • 1970-01-01
    • 2018-09-18
    • 1970-01-01
    相关资源
    最近更新 更多