Как я могу сделать что-то, что перехватывает все «необработанные» исключения в приложении WinForms?

85

До сих пор, я просто поставить попробовать / поймать блок вокруг Application.RunвProgram.cs точке входа в программу. Это достаточно хорошо улавливает все исключения в режиме отладки, но когда я запускаю программу без режима отладки, исключения больше не обрабатываются. Я получаю поле необработанного исключения.

Я не хочу, чтобы это случилось. Я хочу, чтобы все исключения перехватывались при работе в режиме без отладки. Программа имеет несколько потоков, и желательно, чтобы все исключения из них перехватывались одним и тем же обработчиком; Я хочу регистрировать исключения в БД. Есть ли у кого-нибудь совет, как это сделать?

Исаак Болинджер
источник

Ответы:

110

Взгляните на пример из документации ThreadException :

public static void Main(string[] args)
{
   // Add the event handler for handling UI thread exceptions to the event.
    Application.ThreadException += new     
  ThreadExceptionEventHandler(ErrorHandlerForm.Form1_UIThreadException);

  // Set the unhandled exception mode to force all Windows Forms errors
  // to go through our handler.
  Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

  // Add the event handler for handling non-UI thread exceptions to the event. 
  AppDomain.CurrentDomain.UnhandledException += new       
  UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
}

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

 if (!AppDomain.CurrentDomain.FriendlyName.EndsWith("vshost.exe")) { ... }

Чтобы предотвратить перехват исключений при отладке.

Может Gencer
источник
1
Я сделал фоновый рабочий, и в обработчике событий dowork я намеренно вызвал исключение нулевой ссылки. Однако это не было обнаружено AppDomain.CurrentDomain.UnhandledException, несмотря на их установку: Application.ThreadException + = new System.Threading.ThreadExceptionEventHandler (Application_ThreadException); Application.SetUnhandledExceptionMode (UnhandledExceptionMode.CatchException); AppDomain.CurrentDomain.UnhandledException + = новый UnhandledExceptionEventHandler (CurrentDomain_UnhandledException);
Исаак Болинджер
4
@IsaacB, фоновый воркер сам ловит исключения. Вы можете проверить исключение в RunWorkerCompleted даже, посмотрев на свойство RunCompletedEventArgs.Error.
Can Gencer
1
Вы можете протестировать обработку исключений для дополнительных потоков, поместив это в OnLoad вашей основной формы. новый поток (() => {выбросить новое исключение ();}). Start ();
Can Gencer
К сожалению, обработка UnhandledException не остановит приложение от завершения :(
Назар Гринко
7
Вместо взлома FriendlyName.EndsWith попробуйте Debugger.IsAttached, который чище.
moltenform
27

В NET 4 определенные исключения больше не перехватываются по умолчанию; как правило, это исключения, которые указывают на (возможно, фатальное) поврежденное состояние исполняемого файла, например AccessViolationException.

Попробуйте использовать тег [HandleProcessCorruptedStateExceptions] перед основным методом, например

using System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptions

[HandleProcessCorruptedStateExceptions]
public static int Main()
{
    try
    {
        // Catch any exceptions leaking out of the program
        CallMainProgramLoop();
    }
    catch (Exception e) // We could be catching anything here
    {
        System.Console.WriteLine(e.Message);
        return 1;
    }
    return 0;
  } 
Карлос П.
источник
Могу ли я использовать AppDomain.CurrentDomain.UnhandledExceptionи Application.ThreadExceptionтоже с [HandleProcessCorruptedStateExceptions]тегом?
Kiquenet 01
18

Хороший пример можно найти на http://www.csharp-examples.net/catching-unhandled-exceptions/ По сути, измените свой основной на:

static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
        Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

        Application.Run(new Form1());
    }

    static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
    {
        MessageBox.Show(e.Exception.Message, "Unhandled Thread Exception");
    }

    static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        MessageBox.Show((e.ExceptionObject as Exception).Message, "Unhandled UI Exception");
    }
Себ
источник
9

Для этого вы можете использовать библиотеку NBug . С минимальной настройкой вроде этого:

NBug.Settings.Destination1 = "Type=Mail;From=me@mycompany.com;To=bugtracker@mycompany.com;SmtpServer=smtp.mycompany.com;";
AppDomain.CurrentDomain.UnhandledException += NBug.Handler.UnhandledException;
Application.ThreadException += NBug.Handler.ThreadException;

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

// These two should come before enabling visual styles or running the application
AppDomain.CurrentDomain.UnhandledException += ...
Application.ThreadException += ...
...
Application.Run(new Form1());
Теоман Сойгуль
источник
1
Пожалуйста. Используйте форум обсуждения проекта NBug, если у вас есть дополнительные вопросы ( nbusy.com/forum/f11 ), или используйте здесь тег [nbug].
Теоман Сойгуль
Конечно, вы также можете подписать «обычный» обработчик событий на событие UnhandledException. См. Msdn.microsoft.com/en-us/library/…
neo2862,
Ребята, на Win7 + VS10, если я подписываюсь на эти события, подписка не запускается, вместо этого появляется обычный диалог Windows Vista / 7 Check Online for a SolutionИли Close the Program... и т.д. Но если я НЕ подписываюсь, я получаю обычное общее .NET Unhandled Exception Окно. Это происходит в сборках Release и Debug, также пробовал установить Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);ничего не меняет.
gideon
@giddy, после обработки исключений следует выйти из приложения с помощью Environment.Exit (1); если вы не хотите, чтобы отображалось окно с ошибкой.
Теоман Сойгуль
@Teo, спасибо за ответ. Я хочу, чтобы появилась моя собственная форма ошибки, а затем я хочу, чтобы приложение закрылось. Но подписка на события никогда не запускается, она просто показывает общий диалог Win Vista / 7, когда обнаруживает исключения. Но если я не подписываюсь, появится диалоговое окно общего необработанного исключения .NET!
gideon