Як я можу зробити щось, що фіксує всі "необроблені" винятки у програмі 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")) { ... }

Щоб запобігти лову винятків під час налагодження.


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 even, переглядаючи властивість RunCompletedEventArgs.Error.
Can Gencer

1
Ви можете перевірити обробку винятків для додаткових потоків, помістивши це в OnLoad основної форми. new Thread (() => {throw new Exception ();}). 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

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 Вікно. Це трапляється як для версій Release, так і для налагодження, також намагався встановити Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);Нічого не змінює.
gideon

@giddy, після обробки винятків слід вийти з програми за допомогою Environment.Exit (1); якщо ви не хочете, щоб відображалося вікно помилки.
Теоман Сойгул,

@Teo дякую за вашу відповідь. Я хочу, щоб з’явилася моя власна форма помилки, а потім я хочу, щоб програма вийшла. Але передплата на події ніколи не запускається, вона лише відображає загальне діалогове вікно Win Vista / 7, коли зустрічає винятки. Але якщо я не підпишусь, з’явиться загальне діалогове діалогове виняток .NET!
gideon
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.