.NET 1.1 Unhandled Exceptions and MSMQ
I will now tell you a tale of exception handling in .NET 1.1. Be warned my fellow travelers that the road is long and treacherous, and unfortunately does not have a happy ending. May this serve as a warning for you travelers who need to deal with .NET, unmanaged code, threads, and exceptions.
So I am writing this Windows Forms application with the .NET Framework 1.1. The Windows Forms Application reads messages from MSMQ (Microsoft Message Queue). And on a ReceiveCompleted event handler I update some model objects with the data read from the message. Simple enough if everything goes right. If everything goes wrong on the other hand, it will lead you deep into issues beyond your control, and will leave you scratching your head in disbelief.
I noticed that my model objects were not getting updated with no output what so ever, from Visual Studio or the application itself. After checking that I was indeed receiving messages from MSMQ, I stepped through the code and noticed that if I stepped over a particular call to a DataSet method the application would just continue to run and not break at the next line. Interesting I thought, that would only happen if an exception was thrown but no unhandled exception message box was ever displayed by Visual Studio.
So I surrounded the offending statements with a try catch handler and lo and behold an exception was being thrown. I had forgotten to add a primary key to the DataSet. I probably should have added exception handling when I wrote the code, but this bothered me. You cannot anticipate every exception that will be thrown when developing a non trivial application, so there will be times when you miss an exception and you the traveler want to be notified of it.
The standard advice for “handling” unhandled exception’s is to define exception handlers in three different places in a Windows Forms application:
1. Surround your Application.Run call with a try … catch block. This will handle exceptions from the main application thread.
2. Add a handler to the Application.ThreadException event. This will handle exception on UI Threads.
3. Add a handler to the AppDomain.CurrentDomain.UnhandledException event. This will handle exceptions on all other threads (worker threads, thread pool threads).
Details on the above three handlers and why you need them can be found in this MSDN article.
Alrighty, armed with that knowledge I implemented the three handlers and fixed the DataSet code. Things didn’t feel right tho. I was pretty certain that even if code running on a thread in the thread pool threw an exception, at least the Visual Studio debugger would notify me of the exception. So I decided to test the unhandled exceptions handlers by manually throwing an exception in the ReceiveCompleted event handler. I debugged the application and ….. nothing happened. The application just continued to run, no notification of an exception from the debugger or the application. The only thing that told me that something was wrong is that my model objects were not getting updated.
I had run into a brick wall on the road to exception handling nirvana. I was dismayed by this news and all hope was lost, until I found this blog entry. What particularly interested me is this quote:
if the unhandled exception [ occurs in ] a thread that began its life in unmanaged code, the CLR eats the exception and allows your app to keep going
Ahhhh the MSMQ ReceiveCompleted event handler is probably being called from a thread created by MSMQ unmanaged code. That is probably the reason why the three unhandled exception handlers were not called.
So as far as I can tell there is no way to handle all unhandled exceptions in a .NET application that interact with unmanaged code with threads. So the lesson learned is that you should identify the spots in your code where the underlying thread could come from unmanaged code and pay particular attention to exception handling within that code.
Note that .NET Framework 2.0 is supposed to address this problem by not swallowing the exception from background and worker pool threads. Stay tuned as I test these changes, and most importantly see if they addressed the issue of swallowing exceptions from threads created from unmanaged code. Hopefully the road will be straighter and have less walls.



June 23rd, 2007 at 7:27 am
hey did you ever verify that .net 2.0 fixes this?