.NET - Какой лучший способ реализовать «обработчик всех исключений» - PullRequest
74 голосов
/ 20 октября 2008

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

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

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

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

Ответы [ 9 ]

32 голосов
/ 29 июня 2009

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

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

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

Выезд:

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. Обрабатывать необработанные исключения Application.ThreadException (WinForms) или DispatcherUnhandledException (WPF) на более высоком уровне.

16 голосов
/ 20 октября 2008

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

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

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

13 голосов
/ 20 октября 2008

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

6 голосов
/ 21 октября 2008

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

Для других тем:

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

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

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

Предостережение: я являюсь автором SafeThread статьи.

4 голосов
/ 20 октября 2008

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

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

2 голосов
/ 21 октября 2008

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

2 голосов
/ 21 октября 2008

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

Вот некоторые функции, которые он имеет (вытащил сразу со страницы):

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

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

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

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

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);

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

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

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

0 голосов
/ 20 мая 2009

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

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

А вот код ErrorHandler: Просто чтобы прояснить: 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...