Expecting (and Handling) the Unexpected

In an earlier post I mentioned that I’m creating an unhandled exception manager inspired by Jeff Atwood’s Friendly Exception Manager. A couple of days ago we found a bug that crashed our application in UAT. Much to my dismay, no friendly exception message whatsoever was displaying for the user under these circumstances. But how could this be? I’m catching all unhandled exceptions for this very purpose!

Or am I? As it turns out, I was catching most, but not all, types of unhandled exceptions. Here’s where I started:
        public void AddHandler()
{
Application.ThreadException += ThreadExceptionHandler;
}
This is pretty simple and is ideally the first method called in your application after initializing your unhandled exception manager. (Those intimately familiar with Jeff Atwood’s version will notice that his exception managers are purely static. None of my objects are static and there are all kinds of interfaces and small helper objects in place, but the spirit remains the same.) The ThreadException event deals specifically with the UI thread. The handler is where the user notification takes place. However, there are two items that are unaccounted for.

First, my application is a combination of WPF and WinForms. The unhandled exception that crashed our application occurred in WinForms. Windows Forms errors do not behave the same way as ThreadExceptions by default and need to be told what to do. MSDN does a nice job of illustrating this somewhat confusing concept. The second thing I neglected was defining the behavior of non-UI thread exceptions. Our application relies heavily on the TPL library which gives us a big reason to be concerned with non-UI thread behavior. Luckily, we can relatively easily handle everything listed above with a few lines of code and an extra event handler (which, in my case, mirrors the functionality of the handler discussed above). The finished code looks like this:
        public void AddHandler()
{
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler;
Application.ThreadException += ThreadExceptionHandler;
}