2008-10-20 1 views
69

Мне интересно, как лучше всего иметь «если все остальное не удается его поймать»..NET - Какой лучший способ реализовать «улавливать все обработчики исключений»

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

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

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

+2

Это функция «Перезапустить диспетчер» в Windows Vista: http://www.danielmoth.com/Blog/2006/10/vista-restart-manager.html – huseyint

+3

Я написал обширное сообщение в блоге об этом: [** Gotta catch 'em all: Обработка исключительных ситуаций с последними событиями в .NET с WinForms **] (http://jonathonreinhart.blogspot.com/2013/03/gotta-catch-em-all-last-chance.html) –

+0

См. также [TaskScheduler.UnobservedTaskException] (https://msdn.microsoft.com/en-us/library/system.threading.tasks.taskscheduler.unobservedtaskexception%28v=vs.110%29.aspx). – HuBeZa

ответ

31

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

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

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

Отъезд:

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) на более высоком уровне.

+0

Обращение с DispatcherUnhandledException разрешило мои проблемы, но забыл обновить вопрос. Thnx для ответа – TimothyP

+19

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

+2

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

16

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

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

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

4

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

Некоторые ссылки на лучшие практики here и here и here (probably the best exception handling article for .net)

+0

, пожалуйста, ссылайтесь на ссылку на «событие необработанного исключения текущего потока», у меня создалось впечатление, что такого не было! –

+0

*** http: //www.codeproject.com/KB/architecture/exceptionbestpractices.aspx*** не найден – Kiquenet

+0

обновленная мертвая ссылка –

13

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

+6

все, кроме исключений из вторичных потоков, потоков таймера и потоков threadpool! –

+2

Я согласен с тем, что если «обработчик исключений» понимается как фактически сделать что-то, чтобы восстановить его, «UnhandledException» AppDomain недостаточно. Однако исходный вопрос, по-видимому, ориентирован только на отчетность об ошибках, а не на восстановление. Для этого этого было бы достаточно. –

+1

@Steven: если задание пула потоков запускается с помощью BeginInvoke, любое исключение из этого потока сортируется по вызывающему потоку при вызове EndInvoke. –

6

На главном потоке, у вас есть следующие варианты:

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

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

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

Logging исключения хороши, но лучше использовать приложения для мониторинга ;-)

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

+0

@ StevenA.Lowe не полная резервная копия исходного кода о CALM? – Kiquenet

2

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

Вот некоторые особенности, которые он (вытянут сразу на странице) (особенно на производственных серверах!):

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

ELMAH классный (мы используем его ветку), но я думаю, что он спросил о не-веб-приложениях. –

+0

Не имеет значения, что я спросил о не-веб-приложениях, это по-прежнему очень полезная информация для других! так что +1 – TimothyP

2

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

0

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

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

а вот код ErrorHandler: Просто сделать: objUser clear-- это объект моделирования appusers (вы можете получить информацию, такие как домен имя, отдел, регион и т. д. для ведения журнала ILog logger - это объект ведения журнала - например,один выполнение лесозаготовительной деятельности StackTrace я - 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 
+0

Это будет ловить исключения только в текущей теме. То есть это малопригодно, если CallTheCodeThatMightThrowException создает или использует другие потоки. –

0

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

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

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

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException); 

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

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); 

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

Смежные вопросы