2010-06-28 29 views
159

Pregunta: Quiero definir un controlador global de excepciones para excepciones no controladas en mi aplicación de consola. En asp.net, se puede definir una en global.asax, y en las ventanas de aplicaciones/servicios, se puede definir de la siguiente manera.NET Controlador global de excepciones en la aplicación de consola

AppDomain currentDomain = AppDomain.CurrentDomain; 
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyExceptionHandler); 

Pero, ¿cómo puedo definir un gestor de excepciones global para una aplicación de consola?
currentDomain parece que no funciona (.NET 2.0)?

Editar:

Argh, estúpido error.
En VB.NET, se necesita agregar la palabra clave "AddHandler" al frente de currentDomain, o bien uno no ve el evento UnhandledException en IntelliSense ...
Eso es porque los compiladores VB.NET y C# tratan el manejo de eventos diferentemente.

Respuesta

234

No, esa es la forma correcta de hacerlo. Esto funcionó exactamente como debe ser, algo que se puede trabajar desde quizá:

using System; 

class Program { 
    static void Main(string[] args) { 
     System.AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionTrapper; 
     throw new Exception("Kaboom"); 
    } 

    static void UnhandledExceptionTrapper(object sender, UnhandledExceptionEventArgs e) { 
     Console.WriteLine(e.ExceptionObject.ToString()); 
     Console.WriteLine("Press Enter to continue"); 
     Console.ReadLine(); 
     Environment.Exit(1); 
    } 
} 

Tenga en cuenta que no se puede coger el tipo y carga de archivos excepciones generadas por la fluctuación de esta manera. Suceden antes de que su método Main() comience a ejecutarse. Atraparlos requiere retrasar el jitter, mover el código arriesgado a otro método y aplicarle el atributo [MethodImpl (MethodImplOptions.NoInlining)].

+0

Argh, estúpido error, lo que tenga que añadir AddHandler frente a AppDomain.CurrentDomain para ver "UnhandledException" en VB.NET ... –

+2

lo he implementado usted propuso aquí, pero no quiero salir de la aplicación. Solo quiero iniciar sesión y continuar el proceso (sin 'Console.ReadLine()' o cualquier otra alteración del flujo de programas. Pero lo que obtengo es la excepción que se repite una y otra vez, y de nuevo. –

+1

@SharoRoz Jefri: No puede continuar una vez que obtiene una excepción no controlada. La pila está en mal estado, y esto es terminal. Si tiene un servidor, lo que puede hacer en UnhandledExceptionTrapper es reiniciar el programa con los mismos argumentos de línea de comandos. –

-7

Lo que está intentando debería funcionar de acuerdo con los documentos de MSDN para .Net 2.0. También puede probar una captura/captura en la parte principal alrededor de su punto de entrada para la aplicación de la consola.

static void Main(string[] args) 
{ 
    try 
    { 
     // Start Working 
    } 
    catch (Exception ex) 
    { 
     // Output/Log Exception 
    } 
    finally 
    { 
     // Clean Up If Needed 
    } 
} 

Y ahora su captura se encargará de todo lo que no llamó (en el hilo principal). Puede ser elegante e incluso reiniciar donde estaba si lo desea, o puede dejar que la aplicación muera y registrar la excepción. Agregarías finalmente si querías hacer una limpieza. Cada hilo requerirá su propio manejo de excepción de alto nivel similar al principal.

Editado para aclarar el punto sobre los hilos según lo indicado por BlueMonkMN y se muestra en detalle en su respuesta.

+1

Desafortunadamente, todavía pueden lanzarse fuera del bloque Principal(), desafortunadamente. Esto no es en realidad un "atrapa todo" como podrías pensar. Ver la respuesta de @Hans. –

+0

@Mike Primero dije que la forma en que lo está haciendo es correcta, y que él podría intentar un try/catch en general. No estoy seguro de por qué usted (u otra persona) me dio un voto negativo cuando estaba de acuerdo con que Hans acaba de proporcionar otra respuesta que no esperaba obtener un cheque. Eso no es realmente justo, y luego decir que la alternativa es incorrecta sin proporcionar ninguna prueba de cómo una excepción que puede ser detectada por el proceso AppDomain UnhandledException que un try/catch en Main no puede detectar.Me parece grosero decir que algo está mal sin probar por qué está mal, solo decir que es así, no lo hace así. –

+0

Es bastante obvio que usted rechazó 4 de mis publicaciones anteriores de 2009 como represalia. Considera editar tu publicación y deshaceré mi voto negativo (y deberías deshacer los votos negativos que me diste, yo haré lo mismo). –

9

También es necesario controlar las excepciones de hilos:

static void Main(string[] args) { 
Application.ThreadException += MYThreadHandler; 
} 

private void MYThreadHandler(object sender, Threading.ThreadExceptionEventArgs e) 
{ 
    Console.WriteLine(e.Exception.StackTrace); 
} 

chillido, lo siento que era para WinForms, para cualquier hilo que se está usando en una aplicación de consola que tendrá que encerrar en un try/catch bloquear. Los subprocesos de fondo que encuentran excepciones no controladas no hacen que la aplicación finalice.

20

Si tiene una aplicación de subproceso único, puede usar un simple try/catch en la función Main, sin embargo, esto no cubre las excepciones que pueden producirse fuera de la función Main, en otros subprocesos, por ejemplo (como se señaló en otros comentarios).Este código demuestra cómo una excepción puede causar que la aplicación finalice aunque haya tratado de manejarla en Main (observe cómo el programa sale con gracia si presiona enter y permite que la aplicación salga con gracia antes de que se produzca la excepción, pero si la deja ejecutar , que termina muy infeliz):

static bool exiting = false; 

static void Main(string[] args) 
{ 
    try 
    { 
     System.Threading.Thread demo = new System.Threading.Thread(DemoThread); 
     demo.Start(); 
     Console.ReadLine(); 
     exiting = true; 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine("Caught an exception"); 
    } 
} 

static void DemoThread() 
{ 
    for(int i = 5; i >= 0; i--) 
    { 
     Console.Write("24/{0} =", i); 
     Console.Out.Flush(); 
     Console.WriteLine("{0}", 24/i); 
     System.Threading.Thread.Sleep(1000); 
     if (exiting) return; 
    } 
} 

puede recibir una notificación cuando otro hilo se produce una excepción para poder realizar algunas limpiar antes se cierra la aplicación, pero por lo que puedo decir, no se puede, desde una aplicación de consola , obligue a la aplicación a continuar ejecutándose si no maneja la excepción en el hilo desde el que se lanza sin utilizar algunas opciones de compatibilidad poco claras para que la aplicación se comporte como lo haría con .NET 1.x. Este código muestra cómo el hilo principal puede ser notificado de excepciones procedentes de otros hilos, pero todavía terminar con tristeza:

static bool exiting = false; 

static void Main(string[] args) 
{ 
    try 
    { 
     System.Threading.Thread demo = new System.Threading.Thread(DemoThread); 
     AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); 
     demo.Start(); 
     Console.ReadLine(); 
     exiting = true; 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine("Caught an exception"); 
    } 
} 

static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 
{ 
    Console.WriteLine("Notified of a thread exception... application is terminating."); 
} 

static void DemoThread() 
{ 
    for(int i = 5; i >= 0; i--) 
    { 
     Console.Write("24/{0} =", i); 
     Console.Out.Flush(); 
     Console.WriteLine("{0}", 24/i); 
     System.Threading.Thread.Sleep(1000); 
     if (exiting) return; 
    } 
} 

Así que en mi opinión, la forma más limpia de lo manejan en una aplicación de consola es asegurar que cada hilo tiene un manejador de excepciones en el nivel raíz:

static bool exiting = false; 

static void Main(string[] args) 
{ 
    try 
    { 
     System.Threading.Thread demo = new System.Threading.Thread(DemoThread); 
     demo.Start(); 
     Console.ReadLine(); 
     exiting = true; 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine("Caught an exception"); 
    } 
} 

static void DemoThread() 
{ 
    try 
    { 
     for (int i = 5; i >= 0; i--) 
     { 
     Console.Write("24/{0} =", i); 
     Console.Out.Flush(); 
     Console.WriteLine("{0}", 24/i); 
     System.Threading.Thread.Sleep(1000); 
     if (exiting) return; 
     } 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine("Caught an exception on the other thread"); 
    } 
} 
+0

TRY CATCH no funciona en modo de lanzamiento para errores inesperados: / – Muflix

Cuestiones relacionadas