.NET - каков наилучший способ реализовать “обработчик всех исключений”

StackOverflow https://stackoverflow.com/questions/219594

Вопрос

Мне интересно, как лучше всего сделать так, чтобы "если все остальное не сработает, поймай это".

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

Захватывает ли событие AppDomain.CurrentDomain.UnhandledException все?Даже если приложение многопоточное?

Боковое примечание:Windows Vista предоставляет встроенные функции API, которые позволяют любому приложению восстанавливать себя после сбоя...сейчас не могу вспомнить это название...но я бы предпочел не используйте его, как многие наши пользователи по-прежнему используют Windows ХР.

Это было полезно?

Решение

Я только что поиграл с поведением необработанного исключения AppDomain, (это последний этап, на котором регистрируется необработанное исключение)

Да, после обработки обработчиками событий ваше приложение будет закрыто и the nasty "...показано диалоговое окно "программа перестала работать".

:) Ты все еще можно избежать этого.

Проверьте:

class Program
{
    void Run()
    {
        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

        Console.WriteLine("Press enter to exit.");

        do
        {
            (new Thread(delegate()
            {
                throw new ArgumentException("ha-ha");
            })).Start();

        } while (Console.ReadLine().Trim().ToLowerInvariant() == "x");


        Console.WriteLine("last good-bye");
    }

    int r = 0;

    void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        Interlocked.Increment(ref r);
        Console.WriteLine("handled. {0}", r);
        Console.WriteLine("Terminating " + e.IsTerminating.ToString());

        Thread.CurrentThread.IsBackground = true;
        Thread.CurrentThread.Name = "Dead thread";            

        while (true)
            Thread.Sleep(TimeSpan.FromHours(1));
        //Process.GetCurrentProcess().Kill();
    }

    static void Main(string[] args)
    {
        Console.WriteLine("...");
        (new Program()).Run();
    }
}

P.S. Обработайте необработанное для приложения.Исключение ThreadException (WinForms) или DispatcherUnhandledException (WPF) на более высоком уровне.

Другие советы

В ASP.NET вы используете функцию Application_Error в файле Global.asax .

В WinForms вы используете MyApplication_UnhandledException в файле ApplicationEvents

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

Для приложений Winform, в дополнение к AppDomain.CurrentDomain.UnhandledException, я также использую Application.ThreadException и Application.SetUnhandledExceptionMode (w / UnhandledExceptionMode.CatchException). Эта комбинация, кажется, ловит все.

В основном потоке у вас есть следующие опции:

Для других потоков:

  • Вторичные потоки не имеют необработанных исключений;использование Безопасная резьба
  • Рабочие потоки:(таймер, пул потоков) здесь вообще нет никакой системы безопасности!

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

Протоколирование исключений - это хорошо, но мониторинг приложений лучше ;-)

Предостережение:Я являюсь автором книги Безопасная резьба Статья.

Для WinForms не забудьте также присоединить к событию необработанного исключения текущего потока (особенно если вы используете многопоточность).

Некоторые ссылки на лучшие практики здесь и здесь и здесь (вероятно, лучшая статья по обработке исключений для .net)

Есть еще классная штука под названием ЭЛЬМА это будет регистрировать любые ASP.NET ошибки, возникающие в веб-приложении.Я знаю, что вы спрашиваете о решении для приложений Winform, но я почувствовал, что это может быть полезно всем, кому нужны подобные вещи в веб-приложении.Мы используем его там, где я работаю, и это было очень полезно при отладке (особенно на производственных серверах!).

Вот некоторые функции, которые у него есть (взяты прямо со страницы):

  • Протоколирование почти всех необработанных исключений.
  • Веб-страница для удаленного просмотра всего журнала перекодированных исключений.
  • Веб-страница для удаленного просмотра полной информации о любом зарегистрированном исключении.
  • Во многих случаях вы можете просмотреть исходный желтый экран смерти, который ASP.NET сгенерирован для данного исключения, даже при отключенном режиме customErrors .
  • Уведомление по электронной почте о каждой ошибке в момент ее возникновения.
  • RSS-канал с последними 15 ошибками из журнала.
  • Ряд резервных реализаций хранилища для журнала, включая in-memory, Microsoft SQL Server и несколько, внесенных сообществом.

Вы можете отслеживать большинство исключений в этом обработчике даже в многопоточных приложениях, но .NET (начиная с 2.0) не позволит вам отменить необработанные исключения, если вы не включите режим совместимости 1.1. Когда это произойдет, AppDomain будет закрыт, несмотря ни на что. Лучшее, что вы можете сделать, - запустить приложение в другом домене приложений, чтобы вы могли обработать это исключение и создать новый домен приложений для перезапуска приложения.

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

try 
{
    CallTheCodeThatMightThrowException()
 }
catch (Exception ex)
{
    System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace ();
    Utils.ErrorHandler.Trap ( ref objUser, st, ex );
} //eof catch

А вот код обработчика ошибок :Просто чтобы внести ясность- :objUser - это объект, моделирующий пользователей приложения (вы можете получить такую информацию, как доменное имя, отдел, регион и т.д.для целей ведения журнала ILog logger - это объект ведения журнала, напримертот, который выполняет операции протоколирования StackTrace st - объект StackTrace, предоставляющий вам информацию об отладке вашего приложения

using System;
using log4net; //or another logging platform

namespace GenApp.Utils
{
  public class ErrorHandler
  {
    public static void Trap ( Bo.User objUser, ILog logger, System.Diagnostics.StackTrace st, Exception ex )
    {
      if (ex is NullReferenceException)
      { 
      //do stuff for this ex type
      } //eof if

      if (ex is System.InvalidOperationException) 
      {
        //do stuff for this ex type
      } //eof if

      if (ex is System.IndexOutOfRangeException) 
      {
        //do stuff for this ex type
      } //eof if

      if (ex is System.Data.SqlClient.SqlException)
      {
        //do stuff for this ex type
      } //eof if

      if (ex is System.FormatException)
      {
        //do stuff for this ex type
      } //eof if

      if (ex is Exception)
      {
        //do stuff for this ex type
      } //eof catch

    } //eof method 

  }//eof class 
} //eof namesp

В управляемом приложении GUI по умолчанию исключения, возникающие в потоке GUI, обрабатываются тем, что назначено для Application.ThreadException.

Исключения, возникающие в других потоках, обрабатываются AppDomain.CurrentDomain.UnhandledException.

Если вы хотите, чтобы исключения вашего потока GUI работали так же, как и исключения, не относящиеся к GUI, чтобы они обрабатывались AppDomain.CurrentDomain.UnhandledException, вы можете сделать это:

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);

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

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

Вы по-прежнему уязвимы к исключениям из плохо управляемых родных библиотек. Если нативный dll устанавливает свой собственный обработчик, используя Win32 SetUnhandledExceptionFilter, он должен сохранить указатель на предыдущий фильтр и вызвать его тоже. Если этого не произойдет, ваш обработчик не будет вызван.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top