Глобально ловить исключения в приложении WPF? - PullRequest
217 голосов
/ 27 апреля 2009

У нас есть приложение WPF, части которого могут генерировать исключения во время выполнения. Я хотел бы глобально перехватить любое необработанное исключение и записать их в журнал, но в противном случае продолжить выполнение программы, как будто ничего не произошло (вроде VB On Error Resume Next).

Возможно ли это в C #? И если да, то где именно мне нужно поместить код обработки исключений?

В настоящее время я не вижу ни единой точки, где я мог бы обернуть try / catch вокруг, и которая бы улавливала все возможные исключения. И даже тогда я бы оставил все, что было выполнено из-за улова. Или я здесь думаю в совершенно неправильном направлении?

ETA: Поскольку многие люди ниже указали на это: Приложение не для управления атомными электростанциями. Если он выходит из строя, это не так уж важно, но случайные исключения, которые в основном связаны с пользовательским интерфейсом, являются неприятностью в контексте, где он будет использоваться. Их было (и, вероятно, все еще осталось) несколько, и поскольку они используют архитектуру плагинов и могут быть расширены другими (в том числе и студентами), поэтому нет опытных разработчиков, способных написать полностью сообщения об ошибках. свободный код).

Что касается обнаруженных исключений: я регистрирую их в файле журнала, включая полную трассировку стека. В этом весь смысл этого упражнения. Просто чтобы противостоять тем людям, которые слишком буквально воспринимали мою аналогию с OERN В.Б.

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

Для немедленного использования приложения не так много вещей, которые могут произойти с исключением:

  • Нет обработки исключений - диалог ошибок и выход из приложения. Эксперимент должен быть повторен, хотя, вероятно, с другим предметом. Ошибок не было зарегистрировано, что вызывает сожаление.
  • Обобщенная обработка исключений - доброкачественная ошибка в ловушке, никакого вреда. Это должно быть обычным делом, судя по всем ошибкам, которые мы видели во время разработки. Игнорирование ошибок такого рода не должно иметь немедленных последствий; основные структуры данных проверены достаточно хорошо, чтобы они могли легко пережить это.
  • Общая обработка исключений - обнаружена серьезная ошибка, возможно, сбой на более позднем этапе. Такое может случаться редко. Мы никогда не видели это до сих пор. В любом случае ошибка регистрируется, и сбой может быть неизбежным. Так что это концептуально похоже на самый первый случай. За исключением того, что у нас есть трассировка стека. И в большинстве случаев пользователь даже не заметит.

Что касается экспериментальных данных, сгенерированных программой: серьезная ошибка в худшем случае просто не приведет к записи данных. Тонкие изменения, которые слегка изменяют результат эксперимента, маловероятны. И даже в том случае, если результаты кажутся сомнительными, ошибка регистрировалась; все еще можно отбросить эту точку данных, если это общий выброс.

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

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

Ответы [ 6 ]

171 голосов
/ 27 апреля 2009

Используйте Application.DispatcherUnhandledException Event. См. этот вопрос для краткого изложения (см. ответ Дрю Ноакса ).

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

31 голосов
/ 18 октября 2017

Пример кода с использованием NLog , который будет перехватывать исключения, генерируемые из всех потоков в домене , из потока диспетчера пользовательского интерфейса и из асинхронных функций

App.xaml.cs:

public partial class App : Application
{
    private static Logger _logger = LogManager.GetCurrentClassLogger();

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        SetupExceptionHandling();
    }

    private void SetupExceptionHandling()
    {
        AppDomain.CurrentDomain.UnhandledException += (s, e) =>
            LogUnhandledException((Exception)e.ExceptionObject, "AppDomain.CurrentDomain.UnhandledException");

        DispatcherUnhandledException += (s, e) =>
            LogUnhandledException(e.Exception, "Application.Current.DispatcherUnhandledException");

        TaskScheduler.UnobservedTaskException += (s, e) =>
            LogUnhandledException(e.Exception, "TaskScheduler.UnobservedTaskException");
    }

    private void LogUnhandledException(Exception exception, string source)
    {
        string message = $"Unhandled exception ({source})";
        try
        {
            System.Reflection.AssemblyName assemblyName = System.Reflection.Assembly.GetExecutingAssembly().GetName();
            message = string.Format("Unhandled exception in {0} v{1}", assemblyName.Name, assemblyName.Version);
        }
        catch (Exception ex)
        {
            _logger.Error(ex, "Exception in LogUnhandledException");
        }
        finally
        {
            _logger.Error(exception, message);
        }
    }
28 голосов
/ 22 июля 2015

AppDomain.UnhandledException Событие

Это событие предоставляет уведомление о необработанных исключениях. Это позволяет приложение для регистрации информации об исключении перед системой обработчик по умолчанию сообщает об исключении пользователю и завершает применение.

   public App()
   {
      AppDomain currentDomain = AppDomain.CurrentDomain;
      currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);    
   }

   static void MyHandler(object sender, UnhandledExceptionEventArgs args) 
   {
      Exception e = (Exception) args.ExceptionObject;
      Console.WriteLine("MyHandler caught : " + e.Message);
      Console.WriteLine("Runtime terminating: {0}", args.IsTerminating);
   }

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

Например, предположим, что поток запускается в домене приложения "AD1", вызывает метод в домене приложения "AD2", а оттуда вызывает метод в домене приложения "AD3", где он генерирует исключение. первый домен приложения, в котором может быть событие UnhandledException поднял "AD1". Если этот домен приложения не по умолчанию домен приложения, событие также может быть вызвано по умолчанию домен приложения.

17 голосов
/ 14 марта 2011

Кроме того, что упоминалось здесь другими, обратите внимание, что объединение Application.DispatcherUnhandledException (и его похожих ) с

<configuration>
  <runtime>  
    <legacyUnhandledExceptionPolicy enabled="1" />
  </runtime>
</configuration>

в app.config предотвратит исключение приложения вторичными потоками при закрытии приложения.

1 голос
/ 03 ноября 2016

Вот полный пример использования NLog

using NLog;
using System;
using System.Windows;

namespace MyApp
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        private static Logger logger = LogManager.GetCurrentClassLogger();

        public App()
        {
            var currentDomain = AppDomain.CurrentDomain;
            currentDomain.UnhandledException += CurrentDomain_UnhandledException;
        }

        private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            var ex = (Exception)e.ExceptionObject;
            logger.Error("UnhandledException caught : " + ex.Message);
            logger.Error("UnhandledException StackTrace : " + ex.StackTrace);
            logger.Fatal("Runtime terminating: {0}", e.IsTerminating);
        }        
    }


}
0 голосов
/ 27 апреля 2009

Как "VB's On Error Resume Next?" Это звучит немного страшно. Первая рекомендация - не делай этого. Вторая рекомендация - не делай этого и не думай об этом. Вы должны лучше изолировать свои недостатки. От того, как решить эту проблему, зависит то, как ваш код структурирован. Если вы используете шаблон, такой как MVC или тому подобное, то это не должно быть слишком сложно и определенно не потребует проглотителя глобальных исключений. Во-вторых, найдите хорошую библиотеку журналов, такую ​​как log4net, или используйте трассировку. Нам нужно знать больше деталей, например, о каких исключениях вы говорите и какие части вашего приложения могут привести к созданию исключений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...