Archive for November, 2007

h1

AppDomain Events and HttpModules

November 9, 2007

In a previous post I discussed the cause of an error: A process serving application pool terminated unexpectedly.
I realised that I had a need to catch unhandled 2.0 exceptions and started looking at the AppDomain class.

An Application Domain serves as a boundary so that the runtime can isolate applications from one another and using AppDomain.CurrentDomain, you can retrieve the AppDomain instance that a thread is running under.

One of the events of the AppDomain class is the UnhandledException event and it is this that I could utilise to catch any unhandled exception no matter what thread it runs under.

Therefore if I create a new HttpModule I can provide an event handler for this event and can record these exceptions when that is called.

Pooled HttpApplications

One mistake I didn’t want to make though was one that others had made – simply hooking up an event handler in the Init() method of the HttpModule as usual without taking into account multiple application instances…

The ASP.NET pipeline keeps a pool of HttpApplication objects ready to serve requests and each one of these objects has a collection of HttpModules (and thus each HttpModule provides event handlers for its own HttpApplication).

Therefore because for any one AppDomain you have a number of HttpApplication/HttpModule instances I need to ensure that I only hook up to AppDomain events once.

I can achieve this by making the HttpModule thread/multiple instance aware using static members:

public class UnhandledModule : IHttpModule
{
#region static members – note, must be thread safe

static int unhandledExceptionCount = 0;
static object lockObject = new object();
static bool initialized = false;

#endregion

public void Init(HttpApplication context)
{
// We only want one instance of a HttpModule to handle event.
if
( !initialized)
{
// create a lock so no other instance can affect the static variable
lock (lockObject)
{
if( !initialized)
{

AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

initialized = true;
}
} // now lock is released and the static variable is true..
}}}

So with the above code I have ensured that only one HttpModule instance will provide an event handler for the unhandled exception event.
I can be confident that this will not happen multiple times and bloat the memory of the application.

However I have concerns…

The idea for this was obtained from an MSDN article describing the 2.0 unhandled exceptions behaviour change.

What I am concerned about is that because multiple HttpApplication instances are kept in a pool and managed – if any are killed off by the runtime because they are deemed unnecessary (the requests are less frequent for instance), how do I know that the single instance that provided event handler is still alive?

We’ve tested and installed the “UnhandledModule” as described above, yet our application still errors without catching the exception. My current guess is that it is caused by no event handler existing anymore.

I’ve posed this question on the ASP.NET forums and am still figuring out an answer – do the HttpApplication instance all stay alive?
And if not, should I have code in the Dispose() method of the one instance that has the event handler, so it can release the static initialized variable?
Hopefully if I can’t find it, someone out there knows the answer.

h1

A process serving application pool terminated unexpectedly

November 8, 2007

This error message appears on a third party ASP.NET application that we have installed and each time it happens the application seems to be restarting.
What’s more, we have inserted a custom HttpModule into the application that serves as a global event handler… yet this does not catch this particular error.

What is going on?

There are actually two errors we see in the System event log:

A process serving application pool ‘xxxx’ terminated unexpectedly. The process id was ‘yyyy’. The process exit code was ’0×0′.

A process serving application pool ‘xxxx’ suffered a fatal communication error with the World Wide Web Publishing Service. The process id was ‘yyyy’. The data field contains the error number.

Both these errors refer to unhandled exceptions in .NET 2.0 where an error is generated outside of the asp.net request such as a worker thread.
However, this never used to happen in previous frameworks…

In 1.0 and 1.1 any exception that occurred outside the context of a request would cause that thread to die… and that was it. The global error handler would not catch it, it simply died away.
In some applications this was a very bad thing – any open resources in this thread would cause memory leaks and all manner of other unintended consequences.

As such, in 2.0 the default behaviour is for the application to quit – hence these messages in the event log.

Now this is where we can now understand why our HttpModule doesn’t report the error…

Because the exception is outside the context of an asp.request and therefore not part of a HttpApplication/HttpModule process any custom error handlers running from application events do not catch the error.

So how can we catch this error and log it so we can identify the real issue behind the event log error?

I’ve been experimenting with the AppDomain events and in my next post will discuss how I’ve used it to trap these errors and identify where to start to resolve the problem.

h1

IsReusable on the IHttpHandler interface

November 1, 2007

I saw a recent interesting question about HttpHandlers on the ASP.NET forums that I wanted to share:

“What is the purpose of the IsReusable() method on the IHttpHandler interface?”

Well, to answer it we have to understand that a HttpHandler is processed as part of the request life cycle in ASP.NET and for every one of those requests an instance of the appropriate HttpHandler is required.

The IsReusable property enables you to indicate that the same instance can be pooled and used by concurrent requests.

This is useful when you have a lot of initialisation code occurring inside the handler that does not have to be repeated for every single worker thread and request.
For example:

public class MyHandler : IHttpHandler
{
public MyHandler()
{
//constructor logic involves
// a lot of processing and object instantiation
}

#region IHttpHandler Members
public void ProcessRequest(HttpContext context)
{
context.Response.Write(“biscuit”);
}

public bool IsReusable
{
get { return true; }
}
#endregion
}

This illustrates a simple example where the actual processing is writing some text to the context.

So why do we have to worry about whether it is true or false?

We need to make it Thread safe

If you are indicating that the HttpHandler can be re-used then it needs to be programmed with thread safety in mind.
Concurrent requests that can interfere with object state can cause havoc with the results of the handler’s use when it is not thread safe.

Here is an example:

public class MyHandler : IHttpHandler
{

protected
string exampleString;

public MyHandler()
{
//constructor logic involves
// a lot of processing and object instantiation
}

#region IHttpHandler Members
public void ProcessRequest(HttpContext context)
{
exampleString = MyUtility.FromUrl(context.Request.Url.ToString() );

context.Response.Write(exampleString);
}

public bool IsReusable
{
get { return true; }
}
#endregion
}

Between the two lines in the ProcessRequest method there is an opportunity for context switching to interfere with the processing of the handler.
If concurrent requests are using this handler, as one request has retrieved and set the exampleString variable based on url parameters a context switch to a second request thread at the same point means that exampleString is changed to a new value.
When processing switches back to the original request thread, it writes out a potentially different value than the one intended.
Ouch.

Such a problem would probably cause “intermittent” failures and a problem that was potentially hard to pin down.
So if in doubt about thread safety, set the IsReusable method to false.

Otherwise, if you are sure it is thread safe, set to true and pool the handler for potential increased performance in high volume environments.

Follow

Get every new post delivered to your Inbox.