为什么我必须将我的对象两次放入 HttpContext 缓存中才能永久保存它?
Why i have to put my object twice in HttpContext Cache before it keep it for good?
当我将一个对象缓存到 HttpContext Cache
时,我的对象在下次读取时消失,我必须再次重新插入该对象(并非总是如此,但有 90% 的时间)。在那之后,对象就毫无问题地留在那儿了。
事情是这样的:
- 开始调试mvc项目
- 从缓存中读取年龄
- age为null所以我把50放入变量然后插入缓存
- 当对客户端的响应完成后,
CacheItemRemovedCallback
立即执行。 CacheItemRemovedReason
值为 Removed
- 用户点击立即刷新
- 从缓存中读取年龄
- age 仍然是 null 所以我将 50 放入变量中然后将其插入缓存
- 用户点击立即刷新
- 从缓存中读取年龄
- 年龄终于到了!
那么,为什么 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
的卸载事件,我已经能够知道关机原因。 防病毒软件 正在扫描触发 AppDomain
的 FileChangesMonitor
事件的网站文件,该事件随后触发了 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。
当我将一个对象缓存到 HttpContext Cache
时,我的对象在下次读取时消失,我必须再次重新插入该对象(并非总是如此,但有 90% 的时间)。在那之后,对象就毫无问题地留在那儿了。
事情是这样的:
- 开始调试mvc项目
- 从缓存中读取年龄
- age为null所以我把50放入变量然后插入缓存
- 当对客户端的响应完成后,
CacheItemRemovedCallback
立即执行。CacheItemRemovedReason
值为Removed
- 用户点击立即刷新
- 从缓存中读取年龄
- age 仍然是 null 所以我将 50 放入变量中然后将其插入缓存
- 用户点击立即刷新
- 从缓存中读取年龄
- 年龄终于到了!
那么,为什么 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
的卸载事件,我已经能够知道关机原因。 防病毒软件 正在扫描触发 AppDomain
的 FileChangesMonitor
事件的网站文件,该事件随后触发了 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。