【问题标题】:MemoryCache empty just after adding an object添加对象后,MemoryCache 为空
【发布时间】:2011-12-12 12:51:48
【问题描述】:

我在 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 不存在,因此我得到了异常。

我在 Cassini 和 IIS 7 上都对此进行了测试,它似乎与 AppPool 可重用性(在 IIS 7 中启用)无关,我已经测试了多个缓存策略,但无法使其工作

我错过了什么/失败了?

PS:原谅我的英语不好

【问题讨论】:

  • 你有没有一个叫GetLoginInfoGetLoginData的方法,或者这是一个错字?
  • 您确认LoginData.UserLogin(User.Identity.Name); 没有返回空值吗?
  • @DannyTuppeny:setter/getter 的不同名称是我的剪切粘贴中的错字。 UserLogin 方法不返回 null,它从数据库表中读取用户配置文件,顺便说一句,通过检查所有变量进行交叉检查。我怀疑我在缓存中的条目在我添加它之后就被某些东西处理了。将尝试添加 RemoveCallback 以查看是否是这种情况。
  • @BigMike,看起来MemoryCache.Default 是进程范围的。你确定你没有遇到两个线程之间的竞争情况吗?例如,Get() 可能发生在线程 B 上的 Remove()Add() 之间的线程 A 上。
  • @FrédéricHamidi 没有考虑过这种情况,可能是一个很好的见解。实际上应用程序在 ASP.NET 应用程序池中运行(如果他们没有更改它,应该是同一个 IIS 进程的线程池)。明天我一回来工作,我就会调查这件事。谢谢。

标签: asp.net-mvc c#-4.0


【解决方案1】:

使用反编译器查看 MemoryCache 的代码有以下私有函数

private void OnUnhandledException(object sender, UnhandledExceptionEventArgs eventArgs)
{
  if (!eventArgs.IsTerminating)
    return;
  this.Dispose();
}

每个 MemoryCache 都为当前域 Thread.GetDomain() 设置了一个未处理的异常处理程序,因此如果您的应用程序中有任何未捕获的异常,这可能在网站中很常见,它会永久处理 MemoryCache,并且不能这与 IIS 应用程序尤其相关,与仅在未处理的异常时退出的 Windows 应用程序相对。

【讨论】:

  • 有趣。我们现在已经删除了缓存,一旦我们有预算花在那个应用上,我会验证这一点。
【解决方案2】:

MemoryCache 的大小有限。对于Default 实例,不是启发式值(根据MSDN)。

您是否尝试将 CacheItemPolicy 实例上的 Priority 属性设置为 NotRemovable

您可以有竞争条件,因为 SetLoginInfo 中的 Contains-Remove-Add 序列不是原子的 - 尝试改用 Set 方法。

顺便说一句。您正在开发 Web 应用程序,为什么不使用 System.Web.Caching.Cache 来代替?

【讨论】:

  • 嗨奥吉。很久没问这个问题了,代码不是最新的,我会尽快修复它。实际上,我们已经将缓存策略更改为普通的数据库表。 IFRC 我也尝试过使用 Set 方法和 System.Web.Caching.Cache 但没有成功。但是在接下来的几周里,我必须开发一个全新的 MVC 应用程序,我会尝试一下. (我预见到很多缓存,但在专用缓存服务器上,它会很有趣)。但是 +1 给出了很好的提示。谢谢。
【解决方案3】:

我相信您遇到了 Scott Hanselman 确定为 .NET 4 错误的问题。请看这里:MemoryCache Empty : Returns null after being set

【讨论】:

  • 可能你是对的,这个问题已经开放了这么久我几乎忘记了。在我们的应用程序中,我们只是更改了架构以避免使用缓存。
猜你喜欢
  • 2015-03-04
  • 2020-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-17
  • 2019-05-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多