为什么我必须将我的对象两次放入 HttpContext 缓存中才能永久保存它?

Why i have to put my object twice in HttpContext Cache before it keep it for good?

当我将一个对象缓存到 HttpContext Cache 时,我的对象在下次读取时消失,我必须再次重新插入该对象(并非总是如此,但有 90% 的时间)。在那之后,对象就毫无问题地留在那儿了。

事情是这样的:

  1. 开始调试mvc项目
  2. 从缓存中读取年龄
  3. age为null所以我把50放入变量然后插入缓存
  4. 当对客户端的响应完成后,CacheItemRemovedCallback 立即执行。 CacheItemRemovedReason 值为 Removed
  5. 用户点击立即刷新
  6. 从缓存中读取年龄
  7. age 仍然是 null 所以我将 50 放入变量中然后将其插入缓存
  8. 用户点击立即刷新
  9. 从缓存中读取年龄
  10. 年龄终于到了

那么,为什么 Cache 在第一次插入时将对象保留在缓存中会遇到这个问题?

此行为存在于 .Net framework 3.5, 4.0, 4.5, 4.5.2

代码如下:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        int? age = this.HttpContext.Cache.Get("age") as int?;
        if (age == null)
        {
            age = 50;

            this.HttpContext.Cache.Add("age", age, null, DateTime.Now.AddHours(5), TimeSpan.Zero, CacheItemPriority.Default, new CacheItemRemovedCallback(this.CacheItemRemovedCallback));
        }
        return View();
    }

    public void CacheItemRemovedCallback(String key, Object value, CacheItemRemovedReason reason)
    {
    }
}

我的缓存项在他插入后立即被删除的原因是因为 AppDomain 在第一次调用该网站后被卸载。通过捕获 AppDomain 的卸载事件,我已经能够知道关机原因。 防病毒软件 正在扫描触发 AppDomainFileChangesMonitor 事件的网站文件,该事件随后触发了 AppDomain[=] 的 卸载35=].

以下是检测 AppDomain 卸载原因的方法:

Global.asax

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

        AppDomain currentDomain = AppDomain.CurrentDomain;
        currentDomain.DomainUnload += DomainUnloadEventHandler;
    }

    static void DomainUnloadEventHandler(object sender, EventArgs e)
    {
        var httpRuntimeType = typeof(HttpRuntime);

        var httpRuntime = httpRuntimeType.InvokeMember(
            "_theRuntime",
            BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetField,
            null, null, null) as HttpRuntime;

        var shutDownMessage = httpRuntimeType.InvokeMember(
            "_shutDownMessage",
            BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField,
            null, httpRuntime, null) as string;

        string shutDownStack = httpRuntime.GetType().InvokeMember(
            "_shutDownStack",
            BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField,
            null, httpRuntime, null) as string;
    }
}

shutDownMessage 变量包含以下内容:

_shutDownMessage: Change Notification for critical directories.
bin dir change or directory rename
HostingEnvironment initiated shutdown
HostingEnvironment caused shutdown
Change in C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\roota6542f\e317ebf6\hash\hash.web

你有没有看到,hash.web文件是AppDomain卸载的原因。现在,谁在修改这个文件?原来是杀毒软件。通过 停用 McAfee 的按访问扫描程序 ,hash.web 文件不再被更改,因此没有 AppDomain 卸载。问题已解决!

如需了解更多信息,您可以阅读这篇文章blog post