Republished With Permission - Original
Article
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 (note: you can also download a .zip file containing the code
from here):
Listing 1
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(".NETRuntime"))
{
EventLog.CreateEventSource(".NETRuntime", "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);
}
I tried this out using a simple web-site using ASP.NET 2.0
and the built-in VS Web-Server (aka Cassini). When I changed the web.config
file in my running application, the following was logged to my
"Application" event viewer:
Listing 2
_shutDownMessage=CONFIG change
HostingEnvironment caused shutdown
CONFIG change
CONFIG change
_shutDownStack= at
System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
at System.Environment.get_StackTrace()
at
System.Web.HttpRuntime.ShutdownAppDomain()
at
System.Web.Hosting.HostingEnvironment.ShutdownThisAppDomainOnce()
at
System.Web.Hosting.HostingEnvironment.InitiateShutdownWorkItemCallback(Object
state)
at
System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(Object state)
at
System.Threading.ExecutionContext.Run(ExecutionContext executionContext,
ContextCallback callback, Object state)
at
System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(Object state).
When I updated my Global.asax file with some code change,
the following was logged:
Listing 3
_shutDownMessage=Change in GLOBAL.ASAX
Change in GLOBAL.ASAX
Change in GLOBAL.ASAX
HostingEnvironment caused shutdown
_shutDownStack= at
System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
at System.Environment.get_StackTrace()
at System.Web.HttpRuntime.ShutdownAppDomain()
at
System.Web.HttpApplicationFactory.OnAppFileChange(Object sender,
FileChangeEvent e)
at System.Web.DirectoryMonitor.FireNotifications()
at
System.Web.Util.WorkItem.CallCallbackWithAssert(WorkItemCallback callback)
at System.Web.Util.WorkItem.OnQueueUserWorkItemCompletion(Object
state)
at
System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(Object state)
at
System.Threading.ExecutionContext.Run(ExecutionContext executionContext,
ContextCallback callback, Object state)
at
System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(Object state).
And when I changed the contents of my \bin directory I got:
Listing 4
_shutDownMessage=Change Notification for
critical directories.
bin dir change or directory rename
HostingEnvironment caused shutdown
Directory rename change notification for
'E:\Unload'.
Unload dir change or directory rename
_shutDownStack= at
System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
at System.Environment.get_StackTrace()
at System.Web.HttpRuntime.ShutdownAppDomain()
at
System.Web.Hosting.HostingEnvironment.ShutdownThisAppDomainOnce()
at System.Web.Hosting.HostingEnvironment.InitiateShutdownWorkItemCallback(Object
state)
at
System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(Object state)
at
System.Threading.ExecutionContext.Run(ExecutionContext executionContext,
ContextCallback callback, Object state)
at System.Threading.
Hopefully this is a useful trick that you can re-use in your
own applications to get better visibility into what is going on with them. If
you are using ASP.NET 2.0, then you should definitely also investigate the new
ASP.NET 2.0 Health Monitoring feature-set. This provides a rich eventing
architecture for instrumenting your code, as well as raising notifications of
issues to admins when they occur within your application. K. Scott Allen has written a good
overview article of how this new feature-set works, and links to the MSDN
documentation.