7

是否可以在 global.asax 中捕获回收事件?

我知道 Application_End 将被触发,但有没有办法知道它是由应用程序池的回收触发的?

谢谢,Lieven Cardoen 又名 Johlero

4

4 回答 4

7

我在Scott Guthries 的博客上找到了这篇文章:

记录 ASP.NET 应用程序关闭事件

listserv 上的某个人最近询问是否有办法找出 ASP.NET 重新启动应用程序域的原因和时间。具体来说,他正在寻找在生产共享托管环境中的应用程序上触发它们的确切原因(是 web.config 文件更改、global.asax 更改、app_code 目录更改、目录删除更改、最大-num-compilations 达到配额、\bin 目录更改等)。

我团队中的 Thomas 有一个很酷的代码片段,他编写了该代码片段,使用一些漂亮的私有反射技巧来捕获和记录这些信息。它很容易重用和添加到任何应用程序中,并且可以用来在任何你想要的地方记录信息(下面的代码使用 NT 事件日志来保存它——但你可以很容易地将它发送到数据库或通过电子邮件发送给管理员)。该代码适用于 ASP.NET V1.1 和 ASP.NET V2.0。

只需将 System.Reflection 和 System.Diagnostics 命名空间添加到您的 Global.asax 类/文件中,然后使用以下代码添加 Application_End 事件:

public void Application_End() {

    HttpRuntime runtime = 
       (HttpRuntime) typeof(System.Web.HttpRuntime).InvokeMember("_theRuntime",
          BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetField, 
          null, null, null);

    if (runtime == null)
        return;

    string shutDownMessage = 
       (string) runtime.GetType().InvokeMember("_shutDownMessage",
           BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField,
           null, runtime, null);

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

    if (!EventLog.SourceExists(".NET Runtime")) {
        EventLog.CreateEventSource(".NET Runtime", "Application");
    }

    EventLog log = new EventLog();
    log.Source = ".NET Runtime";

    log.WriteEntry(String.Format(
          "\r\n\r\n_shutDownMessage={0}\r\n\r\n_shutDownStack={1}", 
          shutDownMessage, shutDownStack),
       EventLogEntryType.Error);
}
于 2008-11-19T16:59:07.313 回答
3

所以,这是一个如何工作的想法。

根据我之前的回答(附加到 AppDomain.CurrentDomain.ProcessExit)和stephbu的评论:

这将捕获大多数结构化流程的拆解,例如 - 但我不确定它是否会捕获所有的拆解。例如 http://blogs.msdn.com/jmstall/archive/2006/11/26/process-exit-event.aspx 如果进程似乎被挂起,进程回收将终止进程 - 你的处理程序不会被调用。

我建议以下策略:

在(常规)ProcessExit 处理程序(我们假设不会在应用程序池回收时调用)中,将一些文件写入磁盘,如“ app_domain_end_ok.tmp”。

然后在 global.asax 的 Application_Start 中检查这个文件。如果它不存在,则表明应用程序没有以干净的方式终止(或者它是第一次启动)。检查后不要忘记从磁盘中删除此文件。

我自己没有尝试过,但值得一试。

于 2008-11-16T17:56:40.057 回答
1

我自己从未尝试过,但您可以尝试将事件处理程序附加到 AppDomain 的 ProcessExit 事件。

...
AppDomain.CurrentDomain.ProcessExit += new EventHandler(OnExit);
...

void OnExit(object sender, EventArgs e) {
    // do something
}

我希望这有帮助!

于 2008-11-16T17:25:40.850 回答
0

我附加到 DomainUnload 事件要成功得多,它是在 AppPool 回收和 AppPool 本身停止时触发的。

AppDomain.CurrentDomain.DomainUnload += this.CurrentDomainOnProcessExit;

于 2016-11-10T11:48:39.157 回答