ispiro
ispiro

Reputation: 27633

Where should AppDomain.UnhandledException be subscribed to?

The suggested duplicate is about DispatcherUnhandledException, not AppDomain.CurrentDomain.UnhandledException.

Original:

Where should AppDomain.UnhandledException be subscribed to? The example on MSDN just shows it in Main, which is what I do in Winforms: I subscribe to it in Program.Main :

AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

But I can't find a suitable place for it in WPF where Main is hidden. I've searched, but mainly found discussions of whether to subscribe to it, assuming the reader would now where.

Upvotes: 1

Views: 966

Answers (3)

Hans Passant
Hans Passant

Reputation: 941307

The Main() entrypoint in a WPF is auto-generated from the App.xaml source file. Earliest opportunity you have to subscribe the event is in the constructor for the App class in App.xaml.cs:

public partial class App : Application {
    public App() {
        AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
    }

    private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) {
        // etc...
    }
}

This is however not "perfect", you cannot detect any failure in field initializers of your Application class. As well as any JIT compilation failures of types you use in your Application class, missing assemblies or versioning problems being the usual troublemakers.

To avoid missing those, you need to give up on the auto-generated code and write your own Main() method. With the assumption that you did not heavily modify the app.xaml file. Delete that file from the project and add a new class, I'd suggest Program.cs :) And make it look similar to this:

using System;
using System.Runtime.CompilerServices;
using System.Windows;

namespace WpfApplication1 {
    class Program {
        [STAThread]
        public static void Main(string[] args) {
            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
            Start();
        }

        [MethodImpl(MethodImplOptions.NoInlining)]
        private static void Start() {
            var app = new App();
            app.Run(new MainWindow());
        }

        private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) {
            // etc..
        }
    }

    public class App : Application {
        // etc..
    }
}

Upvotes: 2

Kryptos
Kryptos

Reputation: 875

Assuming you created the project with the default template in Visual Studio, you should have a file named app.xaml and under it another file named app.xaml.cs.

Inside the App class you can add it at the beginning of OnStartup (along with the Dispatcher.UnhandledException):

protected override void OnStartup(StartupEventArgs e)
{
    // don't forget to call base implementation
    base.OnStartup(e);

    Dispatcher.UnhandledException += Dispatcher_UnhandledException;
    AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
}

Actually, Dispatcher.UnhandledException should be sufficient in most cases. Meaning you can skip using AppDomain.CurrentDomain.UnhandledException altogether. The only reason to also register to AppDomain.CurrentDomain.UnhandledException would be to get exceptions raised in threads other than the main UI thread. But I think that it is better practice to actually catch those exceptions in their respective thread.

Upvotes: 3

Patrick Hofman
Patrick Hofman

Reputation: 156938

You can override the OnStartup method in your App.xaml.cs, which is the closest you get to the Main method (or use the App constructor` if you will)

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        // register the event handler here
        AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
    }
}

Note that this requires you to omit the StartupUri and open a Window yourself.

Upvotes: 1

Related Questions