IIS回收Global.asax

7

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

我知道应用程序的结束会被触发,但是有没有一种方法可以知道它是由应用程序池的回收触发的呢?

谢谢,Johlero(Lieven Cardoen)


应用程序回收可以是一个相当残酷的过程,这取决于你的进程状态 - 最糟糕的情况是调用Win32::TerminateProcess。在你的进程中无法捕获这样的结果。你想要实现什么目标?清除一些状态吗? - stephbu
4个回答

7
我在Scott Guthries's blog上发现了这篇文章: 记录ASP.NET应用程序关闭事件 最近,一个列表中的人问是否有办法找出为什么和何时ASP.NET重启应用程序域。他特别想知道在生产共享托管环境中触发它们的确切原因(是web.config文件更改、global.asax更改、app_code目录更改、目录删除更改、达到最大编译配额、\bin目录更改等)。
我的团队成员Thomas有一个很酷的代码片段,它使用一些巧妙的私有反射技巧来捕获和记录此信息。它非常容易重用并添加到任何应用程序中,并且可以在任何你想要的地方记录信息(下面的代码使用NT事件日志来保存它 - 但是你也可以将其轻松地发送到数据库或通过电子邮件发送给管理员)。该代码适用于ASP.NET V1.1和ASP.NET V2.0。
只需向Global.asax类/文件添加System.Reflection和System.Diagnostics命名空间,然后添加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);
}

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中检查这个文件。如果不存在,说明应用程序没有以清洁的方式终止(或者是第一次启动)。检查后不要忘记从磁盘中删除此文件。我自己没有尝试过,但这可能值得一试。

我还没有验证过,但我怀疑进程回收器有两种策略 - 1)发送终止进程信号并在轮询进程退出时等待 - 在正常情况下应该触发ProcessExit。2)在等待超时后杀死PID。 - stephbu

1

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

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

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

希望这能有所帮助!


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

0

我在附加到DomainUnload事件方面更加成功,它会在AppPool回收和AppPool本身停止时触发。

AppDomain.CurrentDomain.DomainUnload += this.CurrentDomainOnProcessExit;


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接