2008-10-20 10 views
69

? Me pregunto cuál es la mejor manera de tener un "si todo lo demás falla, póngalo"..NET: ¿Cuál es la mejor manera de implementar un controlador de excepciones "catch all"

quiero decir, que está manejando la mayor cantidad posible de excepciones en su aplicación, pero aún no están obligados a ser los insectos, por lo que necesita tener algo que capturas todas las excepciones no controladas para que pueda recoger y almacenar información en una base de datos o enviarlos a un servicio web.

¿El evento AppDomain.CurrentDomain.UnhandledException captura todo? Incluso si la aplicación es multiproceso?

Nota al margen: Windows Vista expone funciones API nativas que permiten a cualquier aplicación para recuperar sí mismo después de un accidente ... no se puede pensar en el nombre ahora ... pero prefiero no utilizarlo, ya que muchos de nuestros usuarios todavía usan Windows XP.

+2

Es la función "Restart Manager" en Windows Vista: http://www.danielmoth.com/Blog/2006/10/vista-restart-manager.html – huseyint

+3

Escribí una extensa publicación de blog sobre esto: [** Tengo que atraparlos a todos: manejo de excepciones de última oportunidad en .NET con WinForms **] (http://jonathonreinhart.blogspot.com/2013/03/gotta-catch-em-all-last-chance.html) –

+0

See también [TaskScheduler.UnobservedTaskException] (https://msdn.microsoft.com/en-us/library/system.threading.tasks.taskscheduler.unobservedtaskexception%28v=vs.110%29.aspx). – HuBeZa

Respuesta

31

yo sólo he jugado con el comportamiento UnhandledException del dominio de aplicación, (esta es la última etapa de la excepción no controlada se ha registrado en)

Sí, después de procesar los controladores de eventos se dará por finalizada su aplicación y se mostrará el desagradable "... programa detenido en el cuadro de diálogo de trabajo".

:) Usted todavía puede evitar eso.

Salida:

class Program 
{ 
    void Run() 
    { 
     AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); 

     Console.WriteLine("Press enter to exit."); 

     do 
     { 
      (new Thread(delegate() 
      { 
       throw new ArgumentException("ha-ha"); 
      })).Start(); 

     } while (Console.ReadLine().Trim().ToLowerInvariant() == "x"); 


     Console.WriteLine("last good-bye"); 
    } 

    int r = 0; 

    void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 
    { 
     Interlocked.Increment(ref r); 
     Console.WriteLine("handled. {0}", r); 
     Console.WriteLine("Terminating " + e.IsTerminating.ToString()); 

     Thread.CurrentThread.IsBackground = true; 
     Thread.CurrentThread.Name = "Dead thread";    

     while (true) 
      Thread.Sleep(TimeSpan.FromHours(1)); 
     //Process.GetCurrentProcess().Kill(); 
    } 

    static void Main(string[] args) 
    { 
     Console.WriteLine("..."); 
     (new Program()).Run(); 
    } 
} 

P. S. Controle el no administrado para Application.ThreadException (WinForms) o DispatcherUnhandledException (WPF) en el nivel superior.

+0

El manejo de DispatcherUnhandledException resolvió mis problemas, pero olvidé actualizar la pregunta. Thnx para la respuesta – TimothyP

+19

Supongo que es justo mencionar que el código de arriba deja cada hilo fallido por siempre. Es decir. tarde o temprano tendrás montones de hilos zombies rondando. Personalmente, no me parece muy útil. –

+2

Estoy de acuerdo. Eso produjo zombies. En tristeza, acepto esta alternativa para matar mi aplicación inmediatamente después de que el controlador salga. Después de todo, antes de dejar que el hilo muerto duerma para siempre, puede enviar un informe a su servidor, dejar que el usuario finalice las tareas a mano y salir (o reiniciar la aplicación) con elegancia. –

16

En ASP.NET, utilice la función Application_Error en el archivo Global.asax.

En WinForms, se utiliza el MyApplication_UnhandledException en el archivo ApplicationEvents

Ambas funciones son llamados si una excepción no controlada se produce en el código. Puede registrar la excepción y presentar un mensaje agradable al usuario desde estas funciones.

4

Para WinForms, no olvide adjuntar también al evento de excepción no controlada del subproceso actual (especialmente si está utilizando multi threading).

Algunos enlaces en las mejores prácticas y herehere y here (probably the best exception handling article for .net)

+0

por favor enlace a una referencia al "evento de excepción no controlada del Thread actual", ¡tenía la impresión de que no existía tal cosa! –

+0

*** http: //www.codeproject.com/KB/architecture/exceptionbestpractices.aspx*** no encontrado – Kiquenet

+0

se ha actualizado el enlace muerto –

13

Para aplicaciones Winform, además de AppDomain.CurrentDomain.UnhandledException también uso Application.ThreadException y Application.SetUnhandledExceptionMode (w/UnhandledExceptionMode.CatchException). Esta combinación parece atrapar todo.

+6

todo excepto excepciones en subprocesos secundarios, subprocesos de temporizador y subprocesos de subprocesos! –

+2

Acepto que si se entiende que "la manipulación de la excepción" hace algo para recuperarse de ella, la "Excepción no administrada" de AppDomain no es suficiente. Sin embargo, la pregunta original parecía estar orientada solo a la notificación de errores y no a la recuperación. Para ese propósito solo sería suficiente. –

+1

@Steven: si el trabajo del grupo de subprocesos se inicia a través de BeginInvoke, cualquier excepción de ese subproceso se clasifica al subproceso de llamada cuando se llama a EndInvoke. –

6

En el hilo principal, dispone de las siguientes opciones:

Para otros hilos:

  • Los subprocesos secundarios no tienen excepciones no controladas; use SafeThread
  • Subprocesos de trabajo: (timer, threadpool) ¡no hay ninguna red de seguridad en absoluto!

tener en cuenta que estos eventos no mango excepciones, se limitan a informe a la aplicación - a menudo cuando ya es demasiado tarde para hacer algo útil/cuerdo sobre ellos

registro las excepciones son buenas, pero el monitoreo de las aplicaciones es mejor ;-)

Advertencia: soy el autor del artículo SafeThread.

+0

@ StevenA.Lowe no copia de seguridad del código fuente completo acerca de CALM? – Kiquenet

2

También hay algo genial llamado ELMAH que registrará cualquier error de ASP.NET que ocurra en una aplicación web. Sé que estás preguntando acerca de una solución de aplicación de Winform, pero sentí que esto podría ser beneficioso para cualquiera que necesite este tipo de cosas en una aplicación web. La usamos en la que trabajo y ha sido muy útil en la depuración de

Aquí hay algunas características que ha (tirados derecha de la página) (especialmente en servidores de producción!):

  • registro de casi todos excepciones no controladas.
  • Una página web para ver de forma remota todo el registro de excepciones recodificadas.
  • Una página web para ver de forma remota todos los detalles de cualquier excepción registrada.
  • En muchos casos, puede revisar la pantalla amarilla original de la muerte que ASP.NET generó para una excepción dada , incluso con el modo customErrors apagado.
  • Notificación por correo electrónico de cada error en el momento en que ocurre.
  • Una fuente RSS de los últimos 15 errores del registro.
  • Varias implementaciones de almacenamiento de respaldo para el registro, incluyendo en memoria, Microsoft SQL Server y varias contribuidas por la comunidad.
+0

ELMAH es genial (utilizamos una rama) pero creo que preguntó sobre aplicaciones que no son web. –

+0

No importa que haya preguntado sobre aplicaciones que no son web, ¡esta sigue siendo información bastante útil para otros! así que +1 – TimothyP

2

Puede controlar la mayoría de las excepciones en ese manejador incluso en aplicaciones multiproceso, pero .NET (a partir de 2,0) no se permitirá cancelar las excepciones no controladas a menos que active el modo de compatibilidad 1.1. Cuando eso suceda, el AppDomain se cerrará sin importar qué. Lo mejor que puede hacer es iniciar la aplicación en un dominio de aplicación diferente para que pueda manejar esta excepción y crear un nuevo dominio de aplicación para reiniciar la aplicación.

0

estoy usando el siguiente método, que funciona y reduce en gran medida la cantidad de código (todavía no estoy seguro de si hay una manera mejor o lo que las trampas de que podrían ser Siempre que llame a:. I quess la quys dando desventajas serían lo suficientemente educado para aclarar sus acciones;)

try 
{ 
    CallTheCodeThatMightThrowException() 
} 
catch (Exception ex) 
{ 
    System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace(); 
    Utils.ErrorHandler.Trap (ref objUser, st, ex); 
} //eof catch 

Y aquí está el código ManejadorError: sólo para hacer claro-: objUser - es el objeto modelado de los appusers (es posible obtener información como dominio nombre, departamento, región, etc. con fines de registro ILog logger - es el objeto de registro - por ejemplola realización de las actividades de tala StackTrace st - el objeto StackTrace que le da información de depuración para su aplicación

using System; 
using log4net; //or another logging platform 

namespace GenApp.Utils 
{ 
    public class ErrorHandler 
    { 
    public static void Trap (Bo.User objUser, ILog logger, System.Diagnostics.StackTrace st, Exception ex) 
    { 
     if (ex is NullReferenceException) 
     { 
     //do stuff for this ex type 
     } //eof if 

     if (ex is System.InvalidOperationException) 
     { 
     //do stuff for this ex type 
     } //eof if 

     if (ex is System.IndexOutOfRangeException) 
     { 
     //do stuff for this ex type 
     } //eof if 

     if (ex is System.Data.SqlClient.SqlException) 
     { 
     //do stuff for this ex type 
     } //eof if 

     if (ex is System.FormatException) 
     { 
     //do stuff for this ex type 
     } //eof if 

     if (ex is Exception) 
     { 
     //do stuff for this ex type 
     } //eof catch 

    } //eof method 

    }//eof class 
} //eof namesp 
+0

Esto solo detectará excepciones en el hilo actual. Es decir. es de poca utilidad si CallTheCodeThatMightThrowException crea o usa otros hilos. –

0

En una aplicación GUI administrada, de forma predeterminada, las excepciones que se originan en el hilo de la GUI son manejadas por lo que está asignado a Application.ThreadException.

Las excepciones que se originan en los otros subprocesos son manejadas por AppDomain.CurrentDomain.UnhandledException.

Si desea que sus excepciones hilo GUI que funcionan igual que los de su no-GUI, para que puedan obtener manejados por AppDomain.CurrentDomain.UnhandledException, usted puede hacer esto:

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException); 

Una ventaja de controlar el Las excepciones de subprocesos GUI con ThreadException permiten que el usuario tenga la opción de dejar que la aplicación continúe. Para asegurarse de que no hay archivos de configuración están anulando comportamiento predeterminado, puede llamar a:

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); 

Usted sigue siendo vulnerable a las excepciones de DLL nativos se comporten mal. Si un dll nativo instala su propio controlador utilizando Win32 SetUnhandledExceptionFilter, se supone que guarda el puntero al filtro anterior y lo llama también. Si no hace eso, su manejador no será llamado.

Cuestiones relacionadas