Tag Archives: Exceptions

WPF: Exception Handling

I recommend reading the CLR: Exception Handling post before continuing.

A WPF application provides additional events for processing unhandled exceptions in additional to those already offered by the CLR via the AppDomain. To see this we will create a simple application that adds a Button to the main form and throws an exception when it is pressed. Here is the code added to the to the application code-behind file so we can see which events are fired and in what order.

    public partial class App : Application
    {
        public App()
        {
            AppDomain.CurrentDomain.FirstChanceException +=
                new EventHandler(FirstChance);

            AppDomain.CurrentDomain.UnhandledException +=
                new UnhandledExceptionEventHandler(Unhandled);

            this.DispatcherUnhandledException +=
                new DispatcherUnhandledExceptionEventHandler(AppUnhandled);

            this.Dispatcher.UnhandledException +=
                new DispatcherUnhandledExceptionEventHandler(DispUnhandled);

            this.Dispatcher.UnhandledExceptionFilter +=
                new DispatcherUnhandledExceptionFilterEventHandler(DispFilter);
        }

        static void FirstChance(object sender, FirstChanceExceptionEventArgs e)
        {
            Console.WriteLine("AppDomain.FirstChanceException");
        }

        static void Unhandled(object sender, UnhandledExceptionEventArgs e)
        {
            Console.WriteLine("AppDomain.UnhandledException");
        }

        static void AppUnhandled(object sender, DispatcherUnhandledExceptionEventArgs e)
        {
            Console.WriteLine("Application.UnhandledException");
        }

        static void DispUnhandled(object sender, DispatcherUnhandledExceptionEventArgs e)
        {
            Console.WriteLine("Dispatcher.UnhandledException");
        }

        static void DispFilter(object sender, DispatcherUnhandledExceptionFilterEventArgs e)
        {
            Console.WriteLine("Dispatcher.UnhandledExceptionFilter");
        }
    }

The XAML for adding a Button and the Click event handler that throws an exception is too trivial to bother listing here. When our example is run we get the following.

WPF UnhandledException

Pressing the button gives the following message.

WPF FirstChanceException

MSDN documentation indicates that the user should be given a dialog box with exception details followed by the application exiting. I have never seen the supposed dialog box appear but as we can see above it certainly does terminate. This is actually the same end result as occurs when using a bare console application but we do get some additional events. The sequence of events generated is as follows.

WPF Exception Handling

Dispatcher Exception Handling
A dispatcher in WPF is responsible for managing a queue of messages for a thread and dispatching them in priority order. Each WPF thread has an associated dispatcher and has two events relating to exception handling.

The first is UnhandledExceptionFilter which has the sole purpose of allowing you to decide if the exception event of the Dispatcher and Application should fire. It does not however prevent the exception from propagating to the default application domain and terminating the application. If you have some standard logic inside the dispatcher/application instances and for some reason you want to avoid it being called you could handle this event.

When the filter does not prevent it the Dispatcher.UnhandledException event is fired. This allows you to handle the event on a per-thread basis as each thread has its own dispatcher instance. An interesting feature of this event is ability to set the exception as handled and so prevent the application from terminating.

Application Exception Handling
The application instance has the DispatcherUnhandledException event which acts as a central point for any such exception occurring no matter which dispatcher it originated from. So if you have multiple threads and each has its own dispatcher you can choose to hook into the application event and know it will fire no matter which thread the exception originated on. It also has an event argument called Handled that can be used to prevent the exception propagating to the app domain and so exiting the program.

Additional Resources
MSDN – Dispatcher.UnhandledEvent
MSDN – Dispatcher.UnhandledEventFilter
MSDN – Application.DispatcherUnhandledEvent

WinForms: Exception Handling

I recommend reading the CLR: Exception Handling post before continuing.

When building a WinForms application you need to be aware that the default CLR behaviour is modified by WinForms. We can see this most clearly using an example application. Create a new windows forms project and then use the designer to add a Button to the Form1 class. All the project code, excluding the auto-generated code for the Form1 window, is as follows.

    public partial class Form1 : Form
    {
        [STAThread]
        static void Main()
        {
            AppDomain.CurrentDomain.UnhandledException +=
                new UnhandledExceptionEventHandler(Unhandled);

            Application.EnableVisualStyles();
            Application.Run(new Form1());
        }

        static void Unhandled(object sender, UnhandledExceptionEventArgs e)
        {
            Console.WriteLine("UnhandledException Handler");
        }

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            throw new ApplicationException("Button Throw Exception");
        }
    }

When run we get the following window.

WinForms UnhandledException

Pressing the button invokes the button1_click event handler and throws an exception.

WinForms Exception Dialog

Without WinForms we would have expected the CLR to fire the UnhandledException event for the current application domain and then terminate. Instead the user sees the above dialog box. But where did the dialog come from and can we prevent it from appearing?

Message Loop Processing
WinForms is just a wrapper around the Win32 subsystem that uses windows messages for handling eventing in the windowing system. Therefore our application must have a message loop in order to ensure that windows messages are constantly pulled from the message queue and dispatched to the appropriate target window. Without this the user interface would be frozen and unable to respond. This message loop is implemented for us when we call the Application.Run static method.

As application code is always executed from dispatching a windows message it is easy to catch any exception generated by application code. Effectively the dispatch call is contained inside a try/catch which then shows the dialog we have seen above.

Overriding WinForms Dialog
Hook into the Application.ThreadException event in order to implement your own unhandled exception behaviour. Note that the mere act of hooking into this event will prevent WinForms from showing the default dialog. If all you require is to prevent the dialog appearing then simply hook the event with a handler that does nothing.

        [STAThread]
        static void Main()
        {
            Application.ThreadException +=
                new ThreadExceptionEventHandler(ThreadException);
            Application.Run(new Form1());
        }

        static void ThreadException(object sender, ThreadExceptionEventArgs e)
        {
            Console.WriteLine("ThreadException Handler");
        }

Note however that the application will not terminate when the exception is ignored. If you still want the application to terminate you would need to exit the application yourself or you could simply rethrow the exception. The rethrow is outside the WinForms exception handling and so it will obey the usual CLR rules and end up at the application domain UnhandledException handler.

This is the method I would recommend as it means that the same AppDomain.CurrentDomain.UnhandledException handler is fired for non-UI threads as for WinForms threads. Giving complete consistency across your application and a common way of logging problems from all locations. This is the simple code to achieve that.

        [STAThread]
        static void Main()
        {
            AppDomain.CurrentDomain.UnhandledException +=
                new UnhandledExceptionEventHandler(Unhandled);

            Application.ThreadException +=
                new ThreadExceptionEventHandler(ThreadException);

            Application.Run(new Form1());
        }

        static void Unhandled(object sender, UnhandledExceptionEventArgs e)
        {
            Console.WriteLine("UnhandledException Handler");
        }

        static void ThreadException(object sender, ThreadExceptionEventArgs e)
        {
            Console.WriteLine("ThreadException Handler");
            throw e.Exception;
        }

Additional Resources

MSDN – Application.ThreadException
MSDN – Application.SetUnhandledExceptionMode

CLR: Exception Handling

FirstChanceException
Introduced in .NET 4, this notification is fired by an application domain whenever any exception is thrown. Note that this notification does not allow you to alter the exception details or allow it to be marked as handled. After your event handler is processed the exception handled by the CLR in the usual way. But this is a great event for logging all exceptions that occur in your application. Given the copious amounts of output it will produce I would recommend you have a way to turn it on and off as needed.

UnhandledException
This event is fired by the application domain when an exception has been thrown but not caught. When this occurs on your default domain, the once created to host your application, it will terminate immediately afterwards. This is the place to log the exception, provide feedback to the user and then perform necessary cleanup, such as flushing file buffers. All your applications should hook this event and at a minimum log the exception. The next time a user complains your program crashed you can then at least find out the cause of the exception.

Here is a trivial example showing how to hook the events.

class Program
{
    static void Main()
    {
        AppDomain.CurrentDomain.FirstChanceException +=
            new EventHandler(FirstChance);

        AppDomain.CurrentDomain.UnhandledException +=
            new UnhandledExceptionEventHandler(Unhandled);

        throw new ApplicationException("Main Thrown Exception");
    }

    static void FirstChance(object sender, FirstChanceExceptionEventArgs e)
    {
        Console.WriteLine("FirstChanceException Handler");
    }

    static void Unhandled(object sender, UnhandledExceptionEventArgs e)
    {
        Console.WriteLine("UnhandledException Handler");
    }
}

And the console output with the interesting parts in yellow.

AppDomain Exception Handling


Nested Application Domains

The majority of applications have a single application domain that is automatically created at start-up and hosts your assembly. If you have additional domains then the firing of events becomes a little more complicated, but not by much. To see how this works we will create an example where the default domain creates a nested domain called Nested1 which itself has another nested domain called Nested2.

public class Program
{
    static void Main()
    {
        Program.HookFirstChanceException();
        Test t = Program.CreateTestInsideAppDomain("Nested1");
        t.SetupNested1();
        t.ThrowException();
    }

    public static Test CreateTestInsideAppDomain(string appDomainName)
    {
        AppDomain nested = AppDomain.CreateDomain(appDomainName);
        string executingName = Assembly.GetExecutingAssembly().FullName;
        return (Test)nested.CreateInstanceAndUnwrap(executingName, "Test");
    }

    public static void HookFirstChanceException()
    {
        AppDomain.CurrentDomain.FirstChanceException +=
            new EventHandler(FirstChance);
    }

    public static void FirstChance(object sender, FirstChanceExceptionEventArgs e)
    {
        Console.WriteLine("Domain:{0} FirstChanceException Handler",
                          AppDomain.CurrentDomain.FriendlyName);
    }
}

public class Test : MarshalByRefObject
{
    private Test t;

    public void SetupNested1()
    {
        Program.HookFirstChanceException();
        t = Program.CreateTestInsideAppDomain("Nested2");
        t.SetupNested2();
    }

    public void SetupNested2()
    {
        Program.HookFirstChanceException();
    }

    public void ThrowException()
    {
        if (t != null)
            t.ThrowException();
        else
            throw new ApplicationException("Raise Exception");
    }
}

Nested FirstChanceException
All three domains hook into the same FirstChanceException event handler and output to the console. The code is a little more complicated than our first example but this is just the extra fluff needed to create objects inside nested AppDomain instances. Line 8 causes the Test instance inside the Nested2 domain to throw an exception and gives the following output.

Nested FirstChanceException

When the exception is thrown inside Nested2 the FirstChanceException event is fired for the Nested2 domain. Because the exception is not caught the stack is unwound one level which leaves us inside the Nested1 domain. As this is a different domain the FirstChanceException event is fired for the newly encountered domain. Again the exception is not caught so we move up another stack level and reach the Main code itself. Here the default application domain fires the FirstChanceException event because this is again a different application domain to the last one encountered.

I think this is the action you would intuitively expect to occur. The FirstChanceException event is fired each time the stack unwind encounters a different domain to the last time. As soon as any handler is found the unwinding stops and so domains higher up the stack will not be encountered and so not fire the event.

Nested UnhandledException
Modifying the above code to hook the UnhandledException event gives the following.

Nested UnhandledException

Here the UnhandledException event is fired just the once. This indicates that no method on the stack within any domain handled the exception.


Multi-Threaded Scenarios

Most applications make use multiple threads to take advantage of multi-core processors. Often you might not even realise it. The CLR garbage collector runs on a separate thread, WPF applications have a separate render thread, calling BeginInvoke on a Delegate uses a ThreadPool Thread for executing the method asynchronously.

Our new test is little more complicated, it throws an exception from a separate thread whilst nesting calls inside different application domains. This scenario is more complicated than the majority of real world applications but as multi-threaded programming becomes more common it is important to understand it.

public class Program
{
    static void Main()
    {
        Program.HookAppDomainExceptions();
        Test t = Program.CreateTestInsideAppDomain("Nested1");
        t.SetupNested1();
    }

    public static Test CreateTestInsideAppDomain(string appDomainName)
    {
        AppDomain nested1 = AppDomain.CreateDomain(appDomainName);
        string executingName = Assembly.GetExecutingAssembly().FullName;
        return (Test)nested1.CreateInstanceAndUnwrap(executingName, "Test");
    }

    public static void HookAppDomainExceptions()
    {
        AppDomain.CurrentDomain.FirstChanceException +=
            new EventHandler(FirstChance);

        AppDomain.CurrentDomain.UnhandledException +=
            new UnhandledExceptionEventHandler(Unhandled);
    }

    public static void FirstChance(object sender, FirstChanceExceptionEventArgs e)
    {
        Console.WriteLine("Domain:{0} FirstChanceException Handler",
                          AppDomain.CurrentDomain.FriendlyName);
    }

    public static void Unhandled(object sender, UnhandledExceptionEventArgs e)
    {
        Console.WriteLine("Domain:{0} UnhandledException Handler",
                          AppDomain.CurrentDomain.FriendlyName);
    }
}

public class Test : MarshalByRefObject
{
    private delegate void Nothing();

    public void SetupNested1()
    {
        Program.HookAppDomainExceptions();
        Test t = Program.CreateTestInsideAppDomain("Nested2");
        t.SetupNested2();
    }

    public void SetupNested2()
    {
        Program.HookAppDomainExceptions();
        var thread = new Thread(new ThreadStart(ThreadMain));
        thread.Start();
    }

    static void ThreadMain()
    {
        Test t = Program.CreateTestInsideAppDomain("Nested3");
        t.SetupNested3();
    }

    public void SetupNested3()
    {
        Program.HookAppDomainExceptions();
        Test t = Program.CreateTestInsideAppDomain("Nested4");
        t.ThrowException();
    }

    public void ThrowException()
    {
        Program.HookAppDomainExceptions();
        throw new ApplicationException("Raise Exception");
    }
}

And the console output with the interesting parts in yellow.

Multi-Threaded Exceptions


Multi-Threaded FirstChanceException

If you look at the output we can see that the FirstChanceException is thrown for each of the nested domains up to and including Nested2. As this is the domain that creates the separate thread this makes sense. You cannot unwind the stack any further than the start of the thread and the thread was created inside Nested2. This is simple and consistent with the previous examples.

Multi-Threaded UnhandledException
We actually have the UnhandledException fired twice. Once for the domain that contains the terminating thread and then for the default domain. It we had not created any extra domains then only the default domain would have fired. It is only because the extra thread terminated inside a different domain that it fired the UnhandledException event for Nested2.

Asynchronous Delegates
Using BeginInvoke on a delegate allows the delegate to be executed in a separate thread so that your main thread can continue. The CLR implements this by using a Thread from the ThreadPool. We can test this alternate way of generating another thread by replacing the SetupNested2 method with the following code.

    public void SetupNested2()
    {
        Program.HookAppDomainExceptions();
        var start = new Nothing(ThreadStart);
        start.EndInvoke(start.BeginInvoke(null, null));
    }

Note that you have to call EndInvoke to match the original BeginInvoke. There are different ways of synchronising, such as using a wait event or a callback that is fired on completion. But they all produce the same result which can be seen here with the interesting bits highlighted in yellow.

Delegate.BeginInvoke Exceptions

Notice that the FirstChanceException event is fired twice for the Nested2 domain. We can see why by looking at the yellow highlight towards the bottom of the output. The original exception has been rethrown by the EndInvoke. Effectively what we have here is an attempt by the EndInvoke to make the exception look as if it occurred in the original thread and not in the actual ThreadPool Thread.

The rethrow causes that duplicate FirstChanceException event for the Nested2 domain. As the rethrow is now unwinding the original thread, it fires the FirstChanceException for the rest of the domains up to and including the default domain. It also fires the UnhandledException just the once for the default domain. The ThreadPool Thread handled the original exception so that it could be rethrown by EndInvoke and so there is no UnhandledException event for the Nested2 domain, which we encountered in the last test.

You should now be confident handling exceptions in:-

  • Single and multi-threaded applications
  • Single and multi-application domain scenarios
  • Using managed threads directly and via BeginInvoke

Additional Resources

MSDN – AppDomain.FirstChanceException
MSDN – AppDomain.UnhandledException
MSDN – Exceptions in Managed Threads