我在MVC 3 ASP.NET应用程序中遇到了一个奇怪的ASP.NET MemoryCaching问题。
每次执行一个动作时,我都会检查它的LoginInfo是否实际存储在MemoryCache中(代码已经简化,但核心如下):
[NonAction]
protected override void OnAuthorization(AuthorizationContext filterContext) {
Boolean autorizzato = false;
LoginInfo me = CacheUtils.GetLoginData(User.Identity.Name);
if (me == null)
{
me = LoginData.UserLogin(User.Identity.Name);
CacheUtils.SetLoginInfo(User.Identity.Name, me);
}
// Test if the object is really in the memory cache
if (CacheUtils.GetLoginData(User.Identity.Name) == null) {
throw new Exception("IMPOSSIBLE");
}
}
GetLoginInfo是:
public static LoginInfo GetLoginData(String Username)
{
LoginInfo local = null;
ObjectCache cache = MemoryCache.Default;
if (cache.Contains(Username.ToUpper()))
{
local = (LoginInfo)cache.Get(Username.ToUpper());
}
else
{
log.Warn("User " + Username + " not found in cache");
}
return local;
}
SetLoginInfo是:
public static void SetLoginInfo (String Username, LoginInfo Info)
{
ObjectCache cache = MemoryCache.Default;
if ((Username != null) && (Info != null))
{
if (cache.Contains(Username.ToUpper()))
{
cache.Remove(Username.ToUpper());
}
cache.Add(Username.ToUpper(), Info, new CacheItemPolicy());
}
else
{
log.Error("NotFound...");
}
}
代码非常简单,但有时(完全随机),只是在将LoginInfo添加到MemoryCache后,结果为空,刚添加的Object不存在,因此我得到了Exception。
我在Cassini和IIS 7上测试这个,它似乎与AppPool可重用性无关(在IIS 7中启用),我已经测试了几个缓存策略,但无法使其工作
我错过了什么/失败了什么?
PS:原谅我的英语不好
答案 0 :(得分:3)
使用decomplier查看MemoryCache的代码,有以下私有函数
private void OnUnhandledException(object sender, UnhandledExceptionEventArgs eventArgs)
{
if (!eventArgs.IsTerminating)
return;
this.Dispose();
}
每个MemoryCache都为当前域Thread.GetDomain()
设置了一个未处理的异常处理程序,因此,如果您的应用程序中没有任何异常处理,这可能在网站中很常见,它会永远处理MemoryCache无法重复使用这与IIS应用程序特别相关,因为Windows应用程序只是在无法处理的例外情况下退出。
答案 1 :(得分:1)
MemoryCache 的大小有限。对于Default实例,不是启发式值(根据MSDN)。
您是否尝试将 CacheItemPolicy 实例上的优先级属性设置为 NotRemovable ?
您可以拥有竞争条件,因为 SetLoginInfo 中的Contains-Remove-Add序列不是原子的 - 请尝试使用Set方法。
顺便说一下。您正在处理Web应用程序,那么为什么不使用System.Web.Caching.Cache呢?
答案 2 :(得分:1)
我相信你遇到了一个Scott Hanselman认定为.NET 4漏洞的问题。请看这里:MemoryCache Empty : Returns null after being set