views:

928

answers:

3

Is it possible to catch an recycle event in the global.asax?

I know Application_End will be triggered but is there a way to know that it was triggered by a recycle of the application pool?

thx, Lieven Cardoen aka Johlero

+1  A: 

I've never tried this myself, but you could try to attach an event handler to the ProcessExit event of the AppDomain.

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

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

I hope this helps!

splattne
This will trap most structured process teardowns e.g. - but I'm not sure that it will trap all tear downs.e.g. http://blogs.msdn.com/jmstall/archive/2006/11/26/process-exit-event.aspxProcess recycle will kill the process if it seems to be hung - your handler wouldn't get called.
stephbu
+2  A: 

So, here is an idea how this could work.

Based on my previous answer (attach to AppDomain.CurrentDomain.ProcessExit) and stephbu's comment:

This will trap most structured process teardowns e.g. - but I'm not sure that it will trap all tear downs. e.g. http://blogs.msdn.com/jmstall/archive/2006/11/26/process-exit-event.aspx Process recycle will kill the process if it seems to be hung - your handler wouldn't get called.

I suggest following strategy:

In the (regular) ProcessExit handler (which we suppose will not be called on a application pool recycling), write some file to disk like "app_domain_end_ok.tmp".

Then in the Application_Start of your global.asax check for this file. If it doesn't exist it is a sign that the application was not terminated in a clean way (or that it is the first time ever it started). Don't forget to delete this file from disk after the check.

I didn't try that myself, but it could be worth a try.

splattne
Thanks @splattne for the credit...
stephbu
I've not validated this but I suspect that process recycler has two strategies - 1) signal terminate process and wait while polling for process exit - it should trigger ProcessExit in normal conditions. 2) On timeout of wait kill PID.
stephbu
+2  A: 

I found this article on Scott Guthries's blog:

Logging ASP.NET Application Shutdown Events

Someone on a listserv recently asked whether there was a way to figure out why and when ASP.NET restarts application domains. Specifically, he was looking for the exact cause of what was triggering them on his application in a production shared hosted environment (was it a web.config file change, a global.asax change, an app_code directory change, a directory delete change, max-num-compilations reached quota, \bin directory change, etc).

Thomas on my team has a cool code-snippet that he wrote that uses some nifty private reflection tricks to capture and log this information. It is pretty easy to re-use and add into any application, and can be used to log the information anywhere you want (the below code use the NT Event Log to save it – but you could just as easily send it to a database or via an email to an admin). The code works with both ASP.NET V1.1 and ASP.NET V2.0.

Simply add the System.Reflection and System.Diagnostics namespaces to your Global.asax class/file, and then add the Application_End event with this code:

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);
}
splattne