Подтвердить что ты не робот

Глобальный обработчик исключений WPF

Иногда при невоспроизводимых обстоятельствах приложение WPF выходит из строя без каких-либо сообщений. Приложение просто мгновенно закрывается.

Где лучшее место для реализации глобального блока Try/Catch. По крайней мере, мне нужно создать почтовый ящик с: "Извините за неудобства..."

4b9b3361

Ответ 2

Вы можете захватить необработанные исключения на разных уровнях:

Вы должны рассмотреть, какой уровень вам нужен, чтобы захватить необработанные исключения в.

Выбор между # 2 и # 3 зависит от того, используете ли вы более одного потока WPF. Это довольно экзотическая ситуация, и если вы не уверены в том, есть вы или нет, то, скорее всего, вы этого не сделали.

Ответ 3

Быстрый пример кода для Application.Dispatcher.UnhandledException:

    public App() :base() {
        this.Dispatcher.UnhandledException += OnDispatcherUnhandledException;
    }

    void OnDispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) {
        string errorMessage = string.Format("An unhandled exception occurred: {0}", e.Exception.Message);
        MessageBox.Show(errorMessage, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
        e.Handled = true;
    }

Я добавил этот код в App.xaml.cs

Ответ 4

Я использую следующий код в своих приложениях WPF, чтобы показать диалоговое окно "Извините за неудобство" всякий раз, когда возникает необработанное исключение. Он показывает сообщение об исключении и спрашивает пользователя, хотят ли они закрыть приложение или игнорировать исключение и продолжить (последний случай удобен, когда происходят нефатальные исключения, и пользователь все еще может продолжать использовать приложение).

В App.xaml добавьте обработчик события запуска:

<Application .... Startup="Application_Startup">

В коде App.xaml.cs добавьте функцию обработчика событий запуска, которая зарегистрирует обработчик событий глобального приложения:

using System.Windows.Threading;

private void Application_Startup(object sender, StartupEventArgs e)
{
    // Global exception handling  
    Application.Current.DispatcherUnhandledException += new DispatcherUnhandledExceptionEventHandler(AppDispatcherUnhandledException);    
}

void AppDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{    
    \#if DEBUG   // In debug mode do not custom-handle the exception, let Visual Studio handle it

    e.Handled = false;

    \#else

    ShowUnhandledException(e);    

    \#endif     
}

void ShowUnhandledException(DispatcherUnhandledExceptionEventArgs e)
{
    e.Handled = true;

    string errorMessage = string.Format("An application error occurred.\nPlease check whether your data is correct and repeat the action. If this error occurs again there seems to be a more serious malfunction in the application, and you better close it.\n\nError: {0}\n\nDo you want to continue?\n(if you click Yes you will continue with your work, if you click No the application will close)",

    e.Exception.Message + (e.Exception.InnerException != null ? "\n" + 
    e.Exception.InnerException.Message : null));

    if (MessageBox.Show(errorMessage, "Application Error", MessageBoxButton.YesNoCancel, MessageBoxImage.Error) == MessageBoxResult.No)   {
        if (MessageBox.Show("WARNING: The application will close. Any changes will not be saved!\nDo you really want to close it?", "Close the application!", MessageBoxButton.YesNoCancel, MessageBoxImage.Warning) == MessageBoxResult.Yes)
    {
        Application.Current.Shutdown();
    } 
}

Ответ 5

Лучший ответ, вероятно, fooobar.com/questions/25861/....

Вот какой код, который показывает, как его использовать:

App.xaml.cs

public sealed partial class App
{
    protected override void OnStartup(StartupEventArgs e)
    {
        // setting up the Dependency Injection container
        var resolver = ResolverFactory.Get();

        // getting the ILogger or ILog interface
        var logger = resolver.Resolve<ILogger>();
        RegisterGlobalExceptionHandling(logger);

        // Bootstrapping Dependency Injection 
        // injects ViewModel into MainWindow.xaml
        // remember to remove the StartupUri attribute in App.xaml
        var mainWindow = resolver.Resolve<Pages.MainWindow>();
        mainWindow.Show();
    }

    private void RegisterGlobalExceptionHandling(ILogger log)
    {
        // this is the line you really want 
        AppDomain.CurrentDomain.UnhandledException += 
            (sender, args) => CurrentDomainOnUnhandledException(args, log);

        // optional: hooking up some more handlers
        // remember that you need to hook up additional handlers when 
        // logging from other dispatchers, shedulers, or applications

        Application.Dispatcher.UnhandledException += 
            (sender, args) => DispatcherOnUnhandledException(args, log);

        Application.Current.DispatcherUnhandledException +=
            (sender, args) => CurrentOnDispatcherUnhandledException(args, log);

        TaskScheduler.UnobservedTaskException += 
            (sender, args) => TaskSchedulerOnUnobservedTaskException(args, log);
    }

    private static void TaskSchedulerOnUnobservedTaskException(UnobservedTaskExceptionEventArgs args, ILogger log)
    {
        log.Error(args.Exception, args.Exception.Message);
        args.SetObserved();
    }

    private static void CurrentOnDispatcherUnhandledException(DispatcherUnhandledExceptionEventArgs args, ILogger log)
    {
        log.Error(args.Exception, args.Exception.Message);
        // args.Handled = true;
    }

    private static void DispatcherOnUnhandledException(DispatcherUnhandledExceptionEventArgs args, ILogger log)
    {
        log.Error(args.Exception, args.Exception.Message);
        // args.Handled = true;
    }

    private static void CurrentDomainOnUnhandledException(UnhandledExceptionEventArgs args, ILogger log)
    {
        var exception = args.ExceptionObject as Exception;
        var terminatingMessage = args.IsTerminating ? " The application is terminating." : string.Empty;
        var exceptionMessage = exception?.Message ?? "An unmanaged exception occured.";
        var message = string.Concat(exceptionMessage, terminatingMessage);
        log.Error(exception, message);
    }
}

Ответ 6

В дополнение к сообщениям выше:

Application.Current.DispatcherUnhandledException

не будет перехватывать исключения, которые выбрасываются из другого потока, а затем основного потока. Вы должны обрабатывать эти исключения в своей реальной теме. Но если вы хотите обработать их в своем глобальном обработчике исключений, вы можете передать его в основной поток:

 System.Threading.Thread t = new System.Threading.Thread(() =>
    {
        try
        {
            ...
            //this exception will not be catched by 
            //Application.DispatcherUnhandledException
            throw new Exception("huh..");
            ...
        }
        catch (Exception ex)
        {
            //But we can handle it in the throwing thread
            //and pass it to the main thread wehre Application.
            //DispatcherUnhandledException can handle it
            System.Windows.Application.Current.Dispatcher.Invoke(
                System.Windows.Threading.DispatcherPriority.Normal,
                new Action<Exception>((exc) =>
                    {
                      throw new Exception("Exception from another Thread", exc);
                    }), ex);
        }
    });

Ответ 7

Чтобы дополнить Томаса, класс Application также имеет DispatcherUnhandledException событие, которое вы можете обработать.

Ответ 8

Полное решение здесь

он очень хорошо объяснил пример кода. Однако будьте осторожны, чтобы он не закрыл приложение. Добавьте строку Application.Current.Shutdown(); для изящного закрытия приложения.

Ответ 9

Как упоминалось выше

Application.Current.DispatcherUnhandledException не будет ловить исключения, которые выбрасываются из другого потока, а затем основного потока.

Это зависит от того, как был создан поток

Один случай, который не обрабатывается Application.Current.DispatcherUnhandledException - это System.Windows.Forms.Timer, для которого Application.ThreadException может использоваться для обработки этих если вы запустите Forms на других потоках, кроме основного потока, вам нужно будет установить Application.ThreadException из каждого такого потока