Are you sure you know the difference between the following events?
Dispatcher.UnhandledException
Application.DispatcherUnhandledException
AppDomain.UnhandledException
TaskScheduler.UnobservedTaskException
My dean in the university has always been saying that the first rule of programming is “Programs should not contain any errors” and the second rule of programming is “There are no programs written without errors”. So, sometimes, I’m sorry, but sh*t happens and uncaught exceptions occur and they fly freely until they reach the top of the execution stack, thus crushing your program. Global exceptions handling exists in order to react somehow to such horrible cases.
There is a bunch of events which fire up when an unhandled exception occurs. Let’s consider what events can help us. The most useful events as we already mentioned are:
- D
ispatcher.UnhandledException
Application.DispatcherUnhandledException
AppDomain.UnhandledException
TaskScheduler.UnobservedTaskException
Exception on a Dispatcher Thread
The difference between the first two events is a little bit slick. The second one catches exceptions from the main UI dispatcher thread, while the first one catches exceptions from a specific UI dispatcher thread. Usually, they are the same, because in 99% of the cases, WPF application has only one UI-thread and because of that, both the events catch exceptions from the same thread, from the main UI thread. The thing is that WPF is not restricted to have only one UI thread. You can create another UI thread with a corresponding Dispatcher. And in that case, you will have to attach your handler to the UnhandledException
event of the first dispatcher and the second dispatcher. Chances that you will never face such a situation in your entire life are very high. So, generally speaking, you are free to attach handlers to any of these events.
Exception on a Worker Thread
An exception might be thrown from any worker thread in your application. In general, you can spawn the worker thread either by using Thread
class directly or the modern API of Tasks. And regarding global exceptions handling, these cases are different. If an exception was thrown from a task, it can be caught only in the TaskScheduler.UnobservedTaskException
. On the contrary, if an exception was thrown from any other thread, except the UI-thread and threads spawned by Tasks, it can be caught only in the AppDomain.UnhandledException
event.
You can’t actually handle the exception in the AppDomain.UnhandledException
event. You can just log it. If you want your application to stay alive, you need to add a directive in the configuration file of your application:
="1.0" ="utf-8"
<configuration>
<runtime>
<legacyUnhandledExceptionPolicy enabled="1" />
</runtime>
</configuration>
Since the release of .NET 4.5, UnobservedTaskException
does not kill the application. If you want to get back the old behavior, you should add the following directive in the configuration file:
="1.0" ="utf-8"
<configuration>
<runtime>
<ThrowUnobservedTaskExceptions enabled="true"/>
</runtime>
</configuration>
By the way, exceptions occurred within Tasks will not be thrown until corresponding tasks are not collected by the GC.
Thank you for visiting my blog. Subscribe to my blog, don’t miss the next exciting post!
Filed under: .NET, C#, CodeProject, WPF Tagged: global-exception-handling, WPF Foundations