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



этот вопрос уже есть ответ здесь:



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



где лучше всего реализовать глобальный Попробовать/catch блок. По крайней мере, я должен реализовать MessageBox с: "извините за неудобства ..."

1081   9  

9 ответов:

вы можете справиться с AppDomain.UnhandledException событие

EDIT: на самом деле, это событие, вероятно, более адекватно: Application.DispatcherUnhandledException

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

  1. AppDomain.CurrentDomain.UnhandledException из всех потоков в AppDomain.
  2. Dispatcher.UnhandledException из одного конкретного потока диспетчера пользовательского интерфейса.
  3. Application.Current.DispatcherUnhandledException С главная поток диспетчера пользовательского интерфейса в вашем приложении WPF.
  4. TaskScheduler.UnobservedTaskException из каждого домена приложения, который использует планировщик задач для асинхронного оперативный.

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

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

небольшой пример кода для приложения.Диспетчер.UnhandledException:

public App() {
    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;
}

Я добавил этот код в приложение.код XAML.cs

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

В Приложение.xaml добавить обработчик событий запуска:

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

В Приложение.код 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();
    } 
}

лучший ответ, вероятно,https://stackoverflow.com/a/1472562/601990.

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

приложение.код 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);
    }
}

В дополнение к постам выше:

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);
        }
    });

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

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

Это объясняется очень хорошо с примером кода. Однако будьте осторожны, чтобы он не закрыл приложение.Добавить строку Приложение.Текущий.Выключение(); чтобы изящно закрыть приложение.

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

приложение.Текущий.DispatcherUnhandledException не поймает исключения, которые выбрасываются из другого потока, а затем основного потока.

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

один случай, который не обрабатывается приложением.Текущий.DispatcherUnhandledException-это система.Окна.Формы.Таймер для какого приложения.ThreadException может использоваться для обработки этих если вы запускаете формы в других потоках чем основной поток вам нужно будет установить приложение.ThreadException от каждого такого потока

Comments

    Ничего не найдено.