Logging UnhandledExceptions in ArcMap
Posted by Dave Bouwman | Posted in .NET, ArcMap | Posted on 14-05-2007
0
I’m guessing a few of you may have seen this dialog before…
This is what you get when there is an unhandled exception in your .NET code
that’s running in ArcMap. And it’s not exactly handy for an end user – what does
a stack trace mean to them? Not much. So the question becomes – can we replace
this dialog with our own, have it inform the user gracefully that an error has
occured, all the while logging the stack trace and other useful information for
the developers/administrators.
I should stop here and note that what I’m trying to catch are truly unhandled
exceptions. Generally issues which occur deep within ArcGIS, and result in some
kind of un-anticipated failure in our custom .NET code. Even with a reasonable
amount of try/catch blocks, these exceptions do occur from time to time, and
they are exceptionally difficult to fix.
In this post, I’m going to tackle intercepting the unhandled exception. Once
you’ve caught the exception and collected the information you need, there are
any number of ways to log the information – custom web services, Enterprise Library
Logging Block, Log4Net etc.
In a future post, I’ll cover some of these.
Catching “Unhandled” Exceptions
From the .NET side of
things there are two ways you can “catch” unhandled exceptions. I say “catch”
because you can’t actually catch them in the typical try/catch/finally sort of
scenario. At .NET 2.0 an unhandled exception will allways cause the application
to exit. While the CLR is shutting things down, it raises events which you
can provide handlers for.
1) AppDomain.UnhandledException Event
This is the king-kahuna, and the story should end right here. Basically, if an unhandled exception occurs in the AppDomain, the AppDomain.UnhandledException
Event gets raised. At
which time you can log whatever you want. Great – problem solved and this post
is over. Only from my testing, this just does not work within ArcMap. After some head scratching, I read this curious
little note in the docs on MSDN…
For certain application models, the UnhandledException event
can be preempted by other events if the unhandled exception occurs in the main
application thread.
No indication as to what other events these may be, and I’m not sure what’s
going on in ArcMap (maybe someone from ESRI can shed some light?) but the end result is that this
event never fires. Thus, we move on to…
2) Application.ThreadException
While somewhat limiting since it only responds to unhandled exceptions that are
on Windows.Forms threads Application.ThreadException
Event provides an opportunity to log the exception before the application exits. And it does work in ArcMap, so it’s part
of a solution.
Example Project
Since I figured this all out by
writing some “research” (read: hacker) code, I thought I’d share it – maybe someone else can
figure out how to get those other unhanded exceptions.
About the code – this is VB.NET, written for ArcGIS Desktop
9.2. It has a total of 5 commands, and an Extension. My goal was to find a way
to centrally handle these exceptions – specifically in my extension.
The first command I created was the NotHandledCommand – which simply throws
an exception in the on_click event. This was my baseline to see if I could catch
this from my extension. The answer is no – you can’t catch an exception that
occurs in the command class itself. More interesting is that throwing an
exception in an ICommand does not cause a JIT window to appear. It looks like
ArcMap is eating the exception. Since I created my first command by
inheriting from BaseCommand, I created another command that directly implements
ICommand – and same thing. I can see why ESRI may want to do this (kepp ArcMap stable), but if you
are going to eat exceptions, please raise an event so developers
can know that an exception has occured.
Anyhow – to address this, we’re creating some new Command/Tool templates which will have
try/catch blocks with the correct logging code baked in (I’ll do a post about
creating custom visual studio templates too because this is super handy).
The next set of commands, ExceptionFormCommand and ExceptionFormTwoCommand
simply open up forms, which have a single button which throws an exception. As I
noted above, since this code is running on a System.Windows.Forms thread, the
exception is caught and the Application.ThreadException Event is raised. In the
extension. I created two commands simply to test it a little more. I then took
this a step further and created a dockable window (ExceptionDocWinCommand) which
also just raises an exception, and yes it also works. Then, to finish it off, I
created a user control (button that throws an exception), which I then put on
the dockable window – and yes – that worked too.
So – you can download the code below. Compile in Visual Studio 2005, run ArcMap and you’ll need to put the commands onto toolbars manually – they’re all in the “AAA Research” category.

And if anyone knows how to correctly
wire up the AppDomain.UnhandledException event, or another way to catch
unhandled exceptions please let me know.


With a dull title like that, I’ll be suprised if anyone reads this right off the bat! Anyhow - I’ve been having some serious stability issues with my home wireless router – a 