¿Cómo puedo hacer algo que capture todas las excepciones 'no controladas' en una aplicación WinForms?

85

Hasta ahora, acabo de poner un bloque try / catch alrededor del Application.Runen el Program.cspunto de entrada al programa. Esto detecta todas las excepciones lo suficientemente bien en el modo de depuración, pero cuando ejecuto el programa sin el modo de depuración, las excepciones ya no se manejan. Recibo el cuadro de excepción no manejado.

No quiero que pase esto. Quiero que se detecten todas las excepciones cuando se ejecuta en modo sin depuración. El programa tiene varios subprocesos y, preferiblemente, todas las excepciones de ellos quedan atrapadas por el mismo controlador; Quiero registrar excepciones en la base de datos. ¿Alguien tiene algún consejo sobre cómo hacer esto?

Isaac Bolinger
fuente

Respuestas:

110

Eche un vistazo al ejemplo de la documentación de 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);
}

Es posible que también desee no detectar excepciones al depurar, ya que esto facilita la depuración. Es algo así como un truco, pero para eso puedes envolver el código anterior con

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

Para evitar la captura de excepciones al depurar.

Puede gencer
fuente
1
Hice un trabajador en segundo plano, y en el controlador de eventos dowork causé intencionalmente una excepción de referencia nula. Sin embargo, no fue capturado por AppDomain.CurrentDomain.UnhandledException a pesar de configurar estos: Application.ThreadException + = new System.Threading.ThreadExceptionEventHandler (Application_ThreadException); Application.SetUnhandledExceptionMode (UnhandledExceptionMode.CatchException); AppDomain.CurrentDomain.UnhandledException + = new UnhandledExceptionEventHandler (CurrentDomain_UnhandledException);
Isaac Bolinger
4
@IsaacB, el trabajador en segundo plano detecta las excepciones. Puede comprobar la excepción en RunWorkerCompleted incluso, mirando la propiedad RunCompletedEventArgs.Error.
Can Gencer
1
Puede probar el manejo de excepciones para subprocesos adicionales colocando esto en el OnLoad de su formulario principal. new Thread (() => {lanzar nueva Excepción ();}). Start ();
Can Gencer
Lamentablemente, el manejo de UnhandledException no impedirá que la aplicación termine :(
Nazar Grynko
7
En lugar del truco FriendlyName.EndsWith, prueba Debugger.IsAttached, que es más limpio.
fundido
27

En NET 4, ciertas excepciones ya no se detectan de forma predeterminada; tienden a ser excepciones que indican un estado corrupto (posiblemente fatal) del ejecutable, como una AccessViolationException.

Intente usar la etiqueta [HandleProcessCorruptedStateExceptions] delante de su método principal, por ejemplo

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
fuente
¿Puedo usar AppDomain.CurrentDomain.UnhandledExceptiony Application.ThreadExceptiontambién con [HandleProcessCorruptedStateExceptions]etiqueta?
Kiquenet
18

Puede encontrar un buen ejemplo en http://www.csharp-examples.net/catching-unhandled-exceptions/ Básicamente, cambie su main a:

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
fuente
9

Puede usar la biblioteca NBug para eso. Con una configuración mínima como esta:

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

Puede comenzar a recopilar información sobre todos los errores no controlados en su aplicación, incluso cuando se implementa en los clientes. Si no desea utilizar una biblioteca de terceros, debe adjuntar a los siguientes eventos:

// These two should come before enabling visual styles or running the application
AppDomain.CurrentDomain.UnhandledException += ...
Application.ThreadException += ...
...
Application.Run(new Form1());
Teoman Soygul
fuente
1
De nada. Use el foro de discusión del proyecto NBug si tiene más preguntas ( nbusy.com/forum/f11 ) o use la etiqueta [nbug] aquí.
Teoman Soygul
Por supuesto, también puede suscribir un controlador de eventos "normal" al evento UnhandledException. Ver msdn.microsoft.com/en-us/library/…
neo2862
Chicos en Win7 + VS10, si me suscribo a estos eventos, la suscripción no se ejecuta, en su lugar aparece el cuadro de diálogo normal de Windows Vista / 7 Check Online for a SolutionO Close the Program... etc. Pero si NO me suscribo, obtengo la excepción genérica normal no controlada de .NET Ventana. Esto sucede tanto en las versiones de lanzamiento como en las de depuración, también intenté configurar Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);No cambia nada.
gideon
@giddy, después de manejar las excepciones, debe salir de la aplicación con Environment.Salir (1); si no desea que se muestre la ventana de error.
Teoman Soygul
@Teo gracias por tu respuesta. Quiero que aparezca mi propio formulario de error y luego quiero que la aplicación salga. Pero la suscripción al evento nunca se ejecuta, solo muestra el cuadro de diálogo genérico de Win Vista / 7 cuando encuentra excepciones. ¡Pero si no me suscribo, aparece el cuadro de diálogo de excepción genérica no controlada de .NET!
gideon