Pages

Thursday, July 1, 2010

Unhandled Exception Handler For WPF Applications

Exception handling is very vital for any software. We use our traditional way of handling exceptions of our code using Try/ Catch / Finally block to handle runtime exceptions.We write our code inside try block and wait for the error being generated from the code, and write our proper handler to handle the Exception if generated while running the code. Compiler handles all these problems and calls the appropriate catch automatically. We write various Catch blocks which handles the exception based on the type of exception that occurs. After the exception is handled properly, the normal execution of the program remains unaffected.

Well this is very normal for any program. Even though we always try to make our code Ultra-Defensive, sometimes we fall in a prank when our client tells us about an Weird Exception that took place in their environment. May be you browse the whole solution to find the problem, and didn't find the actual issue. Yes, there are lots of exceptions that you cannot handle from your code.

Exception on UI Thread (Dispatcher)

Say your client could not install your application properly and missed out a couple of dlls or missed out themes that you might have used from your code. In these scenarios, we need to use a global handler which you want to be executed whenever any exception that is not handled by your code, or exception which is generated in extreme cases. In case of WPF applications, Application.DispatcherUnhandledException comes the most handy in this situation.

WPF application object comes with DispatcherUnhandledException, an event which is generated automatically whenever application is going to be crashed after an exception is generated. Let us generate see the code on how you could handle these situations :

<Application x:Class="UnhandledExceptionHandler.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="Window1.xaml"
    Startup="Application_Startup"
    DispatcherUnhandledException="Application_DispatcherUnhandledException">
    <Application.Resources>
         
    </Application.Resources>
</Application>

In the above code you can see, I have added an Eventhandler for the application. The DispatcherUnhandledException is called whenever the UI thread of the application generated an unhandled exception. To handle the exception we write :


public bool DoHandle { get; set; }
        private void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
        {
            if (this.DoHandle)
            {
                //Handling the exception within the UnhandledExcpeiton handler.
                MessageBox.Show(e.Exception.Message, "Exception Caught", MessageBoxButton.OK, MessageBoxImage.Error);
                e.Handled = true;
            }
            else
            {
                //If you do not set e.Handled to true, the application will close due to crash.
                MessageBox.Show("Application is going to close! ", "Uncaught Exception");
                e.Handled = false;
            }
        }

In the above code, I have placed a boolean property to determine if we need to handle the exception or not. You can see, if the value of DoHandle is true, I have set e.Handled = true and vice-versa.

DispatcherUnhandledExceptionEventArgs comes with few arguments.
1. Exception : This object is the actual Exception that is generated from the application.
2. Dispatcher : You might already know, Dispatcher points to the UI thread.
3. Handled : It determines if the block has already handled the exception. The default value for e.Handled = false, which means, the application still have the exception.


Thus in our case, if you do not put e.Handled = true, the application will eventually crash down.  So it is very important to set the property e.Handled = true after you handle the exception.

Please note : Sometimes, even though you did set e.Handled = true, the application might crash down. This depends on the severity of the Exception.


Exception on Custom Threads


In case of your custom Threads, your exception will not be caught by the DispatcherUnhandledException. This event hooks only the UI thread, and only be called when the UI thread gets an exception which crashes the program. If you need to handle the Exception occurring from Non UI Thread, you can handle the UnhandledException that comes with AppDomain.


If you are not running your Threads in a new AppDomain, you might handle the UnhandledException event of AppDomain, and this would be called whenever any thread that runs on the AppDomain gets an Exception Object. To make it most simple, I have used AppDomain.CurrrentDomain.UnhandledException.

private void Application_Startup(object sender, StartupEventArgs e)
        {
            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
        }

        void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Exception ex = e.ExceptionObject as Exception;
            MessageBox.Show(ex.Message, "Uncaught Thread Exception", MessageBoxButton.OK, MessageBoxImage.Error);
        }

In the above code you can see I have handled the CurrentDomain.UnhandledException. This event will get executed whenever any UnhandledException occurs inside a NonUI Thread.

Sample Application



To demonstrate, I have provided with a sample application. The application has a Button, which generates Exception, three RadioButton to demonstrate the exception on various scenario and one CheckBox to invoke the Exception from inside a Non-UI thread.

If you run the application, you will see the first RadioButton gives you a MessageBox that it is handled within the block which generates the Exception. The 2nd RadioButton will catch the Exception on DispatcherUnhandledException handler, and 3rd will crash the whole application.

Download Sample Application - 50KB

I hope you like this article. Thank  you all for reading.

7 comments:

  1. You can also handle the uncaught exception by throwing it back to the main UI thread. In VB, I do this by using a function named ThrowEx - this simply accepts an exception parameter and throws it. In the handler, I add this code;

    Application.Current.Dispatcher.Invoke(DispatcherPriority.Send, New DispatcherOperationCallback(AddressOf ThrowEx), DirectCast(e.ExceptionObject, Exception))

    Hope that helps someone out there!

    - Stan Stare

    ReplyDelete
  2. Hi stan,

    Thank you for your comment. Yes, you can Throw the exception and handle it from the UI Thread

    Dispather.Invoke(((Action)() => {
    // Your handler here
    }));

    Thank you for your comment. Its really helpful.

    Cheers.

    ReplyDelete
  3. Hello,

    Very nice post on handling exceptions in WPF. I haven't come across to much information on this topic.

    I work for CodeSmith Tools and we created a WPF Exception handling client that does this for Insight. If you are looking for exception reporting for WPF we have a native WPF client already built here (http://www.codesmithtools.com/product/insight).
    Thanks
    -Blake Niemyjski

    ReplyDelete
  4. I tried to run your sample app. And global exception doesn't work in it. When I'm choosing teh second option in this app, there is info about not handled exception and program terminates. I am using .net 4.0 and VS2010.

    ReplyDelete
  5. @Anonymous

    Its bcos app is built that way. Global Exception handler will catch any exception that is from the same Thread.

    ReplyDelete
  6. @Abhishek Sur
    So what is the point of making the example in which the method you've described is not working? Could you show any situation in which I could catch execeptions globally?

    ReplyDelete
  7. @Anonymous

    Where is it not working? In the application, only if you choose "Keep it Unhandled" it will close the application. On any other case, it will handle it properly.

    When you call it using a new Thread, the value of ThrowThreadException is not refreshed so it keeps on throwing the same exception again and again which is handled in background.

    ReplyDelete

Please make sure that the question you ask is somehow related to the post you choose. Otherwise you post your general question in Forum section.