Jak mogę utworzyć coś, co wyłapuje wszystkie „nieobsługiwane” wyjątki w aplikacji WinForms?

85

Aż do teraz, po prostu umieścić blok try / catch wokół Application.Runw Program.cspunkcie wejścia do programu. To wychwytuje wszystkie wyjątki wystarczająco dobrze w trybie debugowania, ale kiedy uruchamiam program bez trybu debugowania, wyjątki nie są już obsługiwane. Otrzymuję nieobsługiwane pole wyjątków.

Nie chcę, żeby to się stało. Chcę, aby wszystkie wyjątki były przechwytywane podczas uruchamiania w trybie bez debugowania. Program ma wiele wątków i najlepiej, aby wszystkie wyjątki od nich były przechwytywane przez tę samą procedurę obsługi; Chcę rejestrować wyjątki w bazie danych. Czy ktoś ma jakieś rady jak to zrobić?

Isaac Bolinger
źródło

Odpowiedzi:

110

Spójrz na przykład z dokumentacji 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);
}

Możesz również chcieć nie wychwytywać wyjątków podczas debugowania, ponieważ ułatwia to debugowanie. To trochę hack, ale w tym celu możesz owinąć powyższy kod za pomocą

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

Aby zapobiec przechwytywaniu wyjątków podczas debugowania.

Can Gencer
źródło
1
Zrobiłem pracownika w tle, aw programie obsługi zdarzeń dowork intencjonalnie spowodowałem wyjątek zerowego odwołania. Jednak nie został on przechwycony przez wyjątek AppDomain.CurrentDomain.UnhandledException pomimo następujących ustawień: Application.ThreadException + = new System.Threading.ThreadExceptionEventHandler (Application_ThreadException); Application.SetUnhandledExceptionMode (UnhandledExceptionMode.CatchException); AppDomain.CurrentDomain.UnhandledException + = new UnhandledExceptionEventHandler (CurrentDomain_UnhandledException);
Isaac Bolinger,
4
@IsaacB, proces roboczy w tle sam przechwytuje wyjątki. Możesz sprawdzić wyjątek nawet w RunWorkerCompleted, patrząc na właściwość RunCompletedEventArgs.Error.
Can Gencer,
1
Możesz przetestować obsługę wyjątków dla dodatkowych wątków, umieszczając to w OnLoad formularza głównego. nowy wątek (() => {wyrzuć nowy wyjątek ();}). Start ();
Can Gencer
Niestety obsługa wyjątku UnhandledException nie zatrzyma zakończenia aplikacji :(
Nazar Grynko
7
Zamiast FriendlyName.EndsWith hack, wypróbuj Debugger.IsAttached, który jest bardziej przejrzysty.
stopiony kształt
27

W NET 4 niektóre wyjątki niejuż domyślnie przechwytywane; są to zazwyczaj wyjątki wskazujące na (prawdopodobnie krytyczny) uszkodzony stan pliku wykonywalnego, na przykład wyjątek AccessViolationException.

Spróbuj użyć tagu [HandleProcessCorruptedStateExceptions] przed główną metodą, np.

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;
  } 
Carlos P
źródło
Czy mogę używać AppDomain.CurrentDomain.UnhandledExceptioni Application.ThreadExceptionteż z [HandleProcessCorruptedStateExceptions]tagiem?
Kiquenet
18

Ładny przykład można znaleźć pod adresem http://www.csharp-examples.net/catching-unhandled-exceptions/ Zasadniczo zmień swój główny na:

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");
    }
Seb
źródło
9

Możesz do tego użyć biblioteki NBug . Przy minimalnej konfiguracji, takiej jak ta:

NBug.Settings.Destination1 = "Type=Mail;[email protected];[email protected];SmtpServer=smtp.mycompany.com;";
AppDomain.CurrentDomain.UnhandledException += NBug.Handler.UnhandledException;
Application.ThreadException += NBug.Handler.ThreadException;

Możesz zacząć zbierać informacje o wszystkich nieobsłużonych błędach w aplikacji, nawet jeśli jest ona wdrożona na klientach. Jeśli nie chcesz korzystać z biblioteki innej firmy, dołącz do poniższych wydarzeń:

// These two should come before enabling visual styles or running the application
AppDomain.CurrentDomain.UnhandledException += ...
Application.ThreadException += ...
...
Application.Run(new Form1());
Teoman Soygul
źródło
1
Nie ma za co. Skorzystaj z forum dyskusyjnego projektu NBug, jeśli masz dodatkowe pytania ( nbusy.com/forum/f11 ) lub użyj tagu [nbug] tutaj.
Teoman Soygul,
Oczywiście można również zasubskrybować „zwykłą” procedurę obsługi zdarzeń do zdarzenia UnhandledException. Zobacz msdn.microsoft.com/en-us/library/…
neo2862.
Chłopaki na Win7 + VS10, jeśli zasubskrybuję te zdarzenia, subskrypcja nie działa, zamiast tego pojawia się zwykłe okno dialogowe Windows Vista / 7 Check Online for a Solutionlub Close the Program... itd. Ale jeśli NIE subskrybuję, otrzymuję zwykły ogólny nieobsługiwany wyjątek .NET Okno. Dzieje się tak w przypadku kompilacji wydania i debugowania, próbowano również ustawić Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);nic nie zmienia.
gideon,
@giddy, po obsłużeniu wyjątków powinieneś wyjść z aplikacji za pomocą Environment.Exit (1); jeśli nie chcesz, aby było wyświetlane okno błędu.
Teoman Soygul
@Teo dzięki za twoją odpowiedź. Chcę, aby pojawił się mój własny formularz błędu, a następnie chcę, aby aplikacja została zamknięta. Ale subskrypcja zdarzeń nigdy nie działa, po napotkaniu wyjątków wyświetla tylko ogólne okno dialogowe Win Vista / 7. Ale jeśli nie zasubskrybuję, pojawi się ogólne okno nieobsługiwanego wyjątku .NET!
gideon,