Exception Handling in WPF

There are 2 overriding principles since .NET 1.0, irrespective of  platform:

  • Only catch exceptions you plan to handle
  • Only catch System.Exception in 1 place
    I whipped up a WinForm project and added a button to the default form.  I then added the following code its code behind:
    private void ThrowExceptionButton_Click(object sender, EventArgs e)
    {
        ArgumentOutOfRangeException exception = new ArgumentOutOfRangeException("New Exception");
        throw exception;
    }
    When I run the app and press the button, I get this:

image

      Then, I added a general try…catch around the Application.Run method in Program.cs:
    try
    {
        Application.Run(new Form1());
    }
    catch (Exception exception)
    {
        MessageBox.Show("Exception occurred: " + exception.Message);
    }

    And I got this:

    image

    All well and good – this has been the standard for years. I then decided to apply the same methodology to a WPF application.

    The first thing I noticed is that there is not an Application.Run method.  Rather, there is this:

    <Application x:Class="Tff.ExceptionHandling.App"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 StartupUri="MainWindow.xaml">
        <Application.Resources>
             
        </Application.Resources>
    </Application>
    

    Which means I can’t put that StartupUri in a general try…catch.  Going over to MSDN, I see that you are supposed to use the Application.Current.DispatcherUnhandledException like so:

    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            Application.Current.DispatcherUnhandledException += 
                new System.Windows.Threading.DispatcherUnhandledExceptionEventHandler(Current_DispatcherUnhandledException);
            base.OnStartup(e);
        }
    
        void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
        {
            //log(e);
            e.Handled = true;
        }
    }

    All well and good.  If I run the app without debugging, the application handles the exception without shutting down.  However if I run the application while debugging, I got this with or without the exception handling:

    image

    Which is different than WinForms…

    So now that I have come to grips with WPF Exceptions on the mainUI thread, what about secondary threads?

    In WinForms, I can do something like this:

    BackgroundWorker backgroundWorker = null;
    public Form1()
    {
        backgroundWorker = new BackgroundWorker();
        backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
        InitializeComponent();
    }
    
    void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        Thread.Sleep(1000);
        ArgumentOutOfRangeException exception = new ArgumentOutOfRangeException("New Exception");
        throw exception;
    }
    
    private void ThrowExceptionOnSecondThreadButton_Click(object sender, EventArgs e)
    {
        backgroundWorker.RunWorkerAsync();
    }

    Sure enough:

    image

    But the important thing is this.  If I start the application without debugging, then nothing happens when the secondary thread has an exception raised – it just ends silently.  Another interesting offshoot of this is that when I add the global try..catch in Program – it doesn’t do anything for the background thread.  Therefore, the debugger still stops when the exception is raised.

    Hopping over to the WCF solution, the effect was exactly the same.  If I am debugging, I get this:

    image

    But if I am not, the thread ends silently.  As just like WinForms, that DispatcherUnhandledException doesn’t matter to the secondary thread.

    Advertisements

    Leave a Reply

    Fill in your details below or click an icon to log in:

    WordPress.com Logo

    You are commenting using your WordPress.com account. Log Out / Change )

    Twitter picture

    You are commenting using your Twitter account. Log Out / Change )

    Facebook photo

    You are commenting using your Facebook account. Log Out / Change )

    Google+ photo

    You are commenting using your Google+ account. Log Out / Change )

    Connecting to %s

    %d bloggers like this: