如何防止HttpRuntime.Cache在ASP.NET 4.5中删除项目? [英] How to prevent HttpRuntime.Cache to remove items in ASP.NET 4.5?

查看:63
本文介绍了如何防止HttpRuntime.Cache在ASP.NET 4.5中删除项目?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是对此问题的跟踪,其中包含矛盾的答案.我也对与最新版本的ASP.NET相关的答案感兴趣.

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

我的代码如下:

  private void ReportRemovedCallback(字符串键,对象值,CacheItemRemovedReason原因){如果(!ApplicationPoolService.IsShuttingDown()){var str = $使用键{key}删除了缓存的项目,并计数了{(值为IDictionary)?. Count},原因为{reason}";LoggingService.Log(LogLevel.Info,str);}}私人IDictionary< int,T>ThreadSafeCacheAccessAction(Action< IDictionary< int,T> ;, bool> action = null){//必要时刷新缓存var dict = HttpRuntime.Cache [CacheDictKey] as IDictionary< int,T> ;;布尔无效=假;如果(dict == null){锁(CacheLockObject){//从模型属性获取到期时间var cacheInfo = typeof(T).GetCustomAttributes(typeof(UseInCachedRepositoryAttribute),继承:true).FirstOrDefault()作为UseInCachedRepositoryAttribute;int absoluteExpiration = cacheInfo?.AbsoluteExpiration ??Constants.Cache.IndefiniteRetention;int slippingExpiration = 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,依赖项:null,absoluteExpiration:DateTime.Now.AddMinutes(absoluteExpiration),滑动Expiration:滑动Expiration <= 0?Cache.NoSlidingExpiration:TimeSpan.FromMinutes(slidingExpiration),优先级:CacheItemPriority.NotRemovable,onRemoveCallback:ReportRemovedCallback);invalidated = true;}} 

根据提供的文档此处,我还在web.config中添加了以下标记:

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

但是,有时会调用 ReportRemovedCallback 进行项目删除.我的感觉是,将忽略来自web.config的缓存配置(文档中明确指出它已过时),并且 CacheItemPriority.NotRemovable 意味着仅非常高的优先级",而不是从不删除".

问题: 是否有一种方法可以说服HttpRuntime.Cache从不删除某些项目?还是应该考虑使用另一种缓存机制?

解决方案

好,所以我已经挖掘了很多,没有明确的答案,但是下面的配置来自

因此,如果物理内存使用率超过90%,它将驱逐缓存项.由于OS倾向于将几乎所有物理内存都用于系统缓存(由任务管理器报告),因此听起来似乎不太可能.

替代

我使用了快来看看MemoryCache ,因为它与 HttpRuntime.Cache 非常相似.它提供了类似的功能,但是缺少 CacheEntryUpdateCallback (您可以提供它,但是如果InvalidArgumentException与 null 不同,则会抱怨InvalidArgumentException).

现在我的代码如下:

  var dict = MemoryCache.Default.Get(CacheDictKey)as IDictionary< int,T> ;;如果(dict == null){锁(CacheLockObject){//从模型属性获取到期时间var cacheInfo = typeof(T).GetCustomAttributes(typeof(UseInCachedRepositoryAttribute),继承:true).FirstOrDefault()作为UseInCachedRepositoryAttribute;int absoluteExpiration = cacheInfo?.AbsoluteExpiration ??Constants.Cache.IndefiniteRetention;int slippingExpiration = cacheInfo?.SlidingExpiration ??Constants.Cache.NoSlidingExpiration;dict = _modelRepository.AllNoTracking.ToList().Where(item => item.PkId!= 0).ToDictionary(item => item.PkId,item => item);var cacheItemPolicy =新的CacheItemPolicy{AbsoluteExpiration = DateTime.Now.AddMinutes(absoluteExpiration),SlidingExpiration = slideExpiration< = 0吗?Cache.NoSlidingExpiration:TimeSpan.FromMinutes(slidingExpiration),优先级= System.Runtime.Caching.CacheItemPriority.NotRemovable,//抛出InvalidArgumentException//UpdateCallback = CacheEntryUpdateCallback};MemoryCache.Default.Add(CacheDictKey,dict,cacheItemPolicy);}} 

经过一些测试,没有任何额外的删除,并且 w3wp.exe 的内存消耗达到了预期的水平.

此答案中提供了更多详细信息.

This is a follow-up to this question, which contains contradictory answers. I am also interested in an answer related to a more recent version of ASP.NET.

My application uses HttpRuntime.Cache to cache some lists of models that should never expire. They are loaded on application warmup and they are changed quite rarely, but read quite often.

My code is the following:

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

Based on the documentation provided here, I have also included the following markup within the web.config:

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

However, from time to time, ReportRemovedCallback is called for item removal. My feeling is that caching configuration from web.config is ignored (the documentation clearly states it is outdated) and that CacheItemPriority.NotRemovable means only "a very high priority", not "never remove".

Question: is there a way to convince HttpRuntime.Cache to never remove some items? Or should I consider another caching mechanism?

解决方案

Ok, so I have dug more and there is no definitive answer, but the following configuration from this old docs seems to apply regardless of trials to deny expiration:

The following default cache element is not explicitly configured in the machine configuration file or in the root Web.config file, but is the default configuration returned by application in the .NET Framework version 2.0.

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

So, if physical memory usage is above 90%, it will evict cache items. Since OS tends to use almost all physical memory for system cache (reported by Task Manager), this is not so unlikely as it sounds.

Alternative

I took MemoryCache for a spin, since it is very similar to HttpRuntime.Cache. It provides similar functionality, but lacks the CacheEntryUpdateCallback (you can provide it, but complains with InvalidArgumentException if it is different from null).

Now my code is the following:

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

After some tests, there were no extra removals and the memory consumption of w3wp.exe raised as expected.

More details are provided within this answer.

这篇关于如何防止HttpRuntime.Cache在ASP.NET 4.5中删除项目?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆