.NET - ¿Cuál es la mejor manera de implementar un controlador de excepciones & # 8220; catch all & # 8221;

StackOverflow https://stackoverflow.com/questions/219594

Pregunta

Me pregunto cuál es la mejor manera de tener un " si todo lo demás falla, cógelo " ;.

Quiero decir, estás manejando tantas excepciones como sea posible en tu aplicación, pero todavía hay errores, así que necesito tener algo que captura todas las excepciones no manejadas para que pueda recopilar información y almacenar en una base de datos o envíelos 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 de API nativas que permiten cualquier aplicación recuperarse después de un choque ... no puedo pensar en el nombre ahora ... pero preferiría no hacerlo úselo, ya que muchos de nuestros usuarios siguen usando Windows XP.

¿Fue útil?

Solución

Acabo de jugar con el comportamiento UnhandledException de AppDomain, (esta es la última etapa en la que se registra la excepción no controlada)

Sí, después de procesar los controladores de eventos, su aplicación finalizará y el desagradable " ... programa de diálogo dejó de funcionar " mostrado.

:) Usted todavía puede evitar eso.

Echa un vistazo:

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. Maneja el no manejado para Application.ThreadException (WinForms) o DispatcherUnhandledException (WPF) en el nivel superior.

Otros consejos

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

En WinForms, usa la MyApplication_UnhandledException en el archivo ApplicationEvents

Se llama a ambas funciones si se produce una excepción no controlada en su código. Puede registrar la excepción y presentar un mensaje agradable al usuario desde estas funciones.

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.

En el hilo principal, tienes las siguientes opciones:

Para otros hilos:

  • Los subprocesos secundarios no tienen excepciones no controladas; use SafeThread
  • Subprocesos de trabajo: (temporizador, conjunto de hilos) ¡no hay ninguna red de seguridad!

Tenga en cuenta que estos eventos no manejan excepciones, simplemente los reportan a la aplicación, a menudo cuando es demasiado tarde para hacer algo útil / sensato sobre ellos

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

Advertencia: soy el autor del artículo SafeThread .

Para WinForms, no olvides adjuntarte al evento de excepción no manejada del Thread actual (especialmente si estás usando subprocesos múltiples).

Algunos enlaces sobre mejores prácticas aquí y here y aquí (probablemente el mejor artículo de manejo de excepciones para .net)

También hay una cosa interesante llamada ELMAH que registrará cualquier error ASP.NET que Ocurren en una aplicación web. Sé que estás preguntando por una solución de la aplicación Winform, pero sentí que esto podría ser beneficioso para cualquiera que necesite este tipo de cosas en una aplicación web. Lo usamos donde trabajo y ha sido muy útil para depurar (¡especialmente en servidores de producción!)

Aquí hay algunas características que tiene (retiradas de la página):

  
      
  • Registro de casi todas las excepciones no controladas.
  •   
  • Una página web para ver de forma remota el registro completo de las excepciones grabadas.
  •   
  • Una página web para ver de forma remota los detalles completos de cualquier excepción registrada.
  •   
  • En muchos casos, puede revisar la pantalla amarilla original de la muerte que   ASP.NET generado para un determinado   excepción, incluso con el modo customErrors   desactivado.
  •   
  • Una notificación por correo electrónico de cada error en el momento en que se produce.
  •   
  • Una fuente RSS de los últimos 15 errores del registro.
  •   
  • Varias implementaciones de almacenamiento de respaldo para el registro, incluidas   en memoria, Microsoft SQL Server y   Varios aportados por la comunidad.
  •   

Puede controlar la mayoría de las excepciones en ese controlador, incluso en aplicaciones multiproceso, pero .NET (a partir de 2.0) no le permitirá cancelar excepciones no controladas a menos que habilite el modo de compatibilidad 1.1. Cuando eso suceda, el AppDomain se cerrará sin importar nada. Lo mejor que podría hacer es iniciar la aplicación en un dominio de aplicación diferente para poder manejar esta excepción y crear un nuevo dominio de aplicación para reiniciar la aplicación.

Estoy usando el siguiente enfoque, que funciona y reduce en gran medida la cantidad de código (pero no estoy seguro de que exista una mejor manera o de cuáles podrían ser las dificultades). Cuando sea que llames: Supongo que los quys dando menos serían lo suficientemente educados 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 ErrorHandler: Solo para aclarar: objUser: es el objeto que modela a los usuarios de la aplicación (puede obtener información como el nombre de dominio, departamento, región, etc. para fines de registro). El registrador ILog es el objeto de registro, por ejemplo, el que realiza las actividades de registro StackTrace st: el objeto StackTrace que le proporciona 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

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

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

Si desea que sus excepciones de subprocesos de la GUI funcionen igual que las de su GUI no, para que sean manejadas por AppDomain.CurrentDomain.UnhandledException, puede hacer esto:

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);

Una ventaja de capturar las excepciones de subprocesos de la GUI mediante ThreadException es que puede dar al uso las opciones de permitir que la aplicación continúe. Para asegurarse de que ningún archivo de configuración anule el comportamiento predeterminado, puede llamar a:

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

Aún eres vulnerable a las excepciones de las dll nativas con un comportamiento inadecuado. Si una dll nativa instala su propio controlador utilizando Win32 SetUnhandledExceptionFilter, se supone que debe guardar el puntero al filtro anterior y llamarlo también. Si no lo hace, no se llamará a su manejador.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top