如何防止HttpRuntime.Cache在ASP.NET 4.5中删除项目? [英] How to prevent HttpRuntime.Cache to remove items in 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 ,因为它与 现在我的代码如下: 经过一些测试,没有任何额外的删除,并且 此答案中提供了更多详细信息. 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 My code is the following: Based on the documentation provided here, I have also included the following markup within the web.config: However, from time to time, 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.
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. I took MemoryCache for a spin, since it is very similar to Now my code is the following: After some tests, there were no extra removals and the memory consumption of More details are provided within this answer. 这篇关于如何防止HttpRuntime.Cache在ASP.NET 4.5中删除项目?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!替代
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
的内存消耗达到了预期的水平.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.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;
}
}
<caching>
<cache disableExpiration="true" disableMemoryCollection="true" />
</caching>
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".
<cache disableMemoryCollection="false"
disableExpiration="false" privateBytesLimit="0"
percentagePhysicalMemoryUsedLimit="90"
privateBytesPollTime="00:02:00" />
Alternative
HttpRuntime.Cache
. It provides similar functionality, but lacks the CacheEntryUpdateCallback
(you can provide it, but complains with InvalidArgumentException if it is different from null
).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
raised as expected.