¿Captar excepciones globalmente en una aplicación WPF?

Resuelto Joey asked hace 15 años • 7 respuestas

Tenemos una aplicación WPF donde partes de ella pueden generar excepciones en tiempo de ejecución. Me gustaría detectar globalmente cualquier excepción no controlada y registrarla, pero de lo contrario continuar la ejecución del programa como si nada hubiera pasado (algo así como VB On Error Resume Next).

¿Es esto posible en C#? Y si es así, ¿dónde exactamente necesitaría colocar el código de manejo de excepciones?

Actualmente no puedo ver ningún punto único en el que pueda ajustar un try/ catchalrededor y que detecte todas las excepciones que puedan ocurrir. Incluso entonces, habría dejado todo lo que se ejecutó debido a la captura. ¿O estoy pensando en direcciones terriblemente equivocadas?

ETA: Porque mucha gente abajo lo ha señalado: La aplicación no es para controlar centrales nucleares. Si falla, no es gran cosa, pero genera excepciones aleatorias que en su mayoría están relacionadas con la interfaz de usuario y que son una molestia en el contexto donde se usaría. Hubo (y probablemente todavía haya) algunos de ellos y, dado que utiliza una arquitectura de complemento y otros pueden ampliarlo (también estudiantes en ese caso, no hay desarrolladores experimentados que puedan escribir código completamente libre de errores).

En cuanto a las excepciones que quedan detectadas: las registro en un archivo de registro, incluido el seguimiento completo de la pila. Ese era el objetivo de ese ejercicio. Sólo para contrarrestar a aquellas personas que estaban tomando mi analogía con el OERN de VB demasiado literalmente.

Sé que ignorar ciegamente ciertas clases de errores es peligroso y podría dañar la instancia de mi aplicación. Como se dijo antes, este programa no es de misión crítica para nadie. Nadie en su sano juicio apostaría a ello la supervivencia de la civilización humana. Es simplemente una pequeña herramienta para probar ciertos enfoques de diseño. Ingeniería de software.

Para el uso inmediato de la aplicación no hay muchas cosas que puedan suceder en una excepción:

  • Sin manejo de excepciones: cuadro de diálogo de error y salida de la aplicación. El experimento debe repetirse, aunque probablemente con otro sujeto. No se han registrado errores, lo cual es lamentable.
  • Manejo de excepciones genérico: error benigno atrapado, sin daño. Este debería ser el caso común a juzgar por todos los errores que vimos durante el desarrollo. Ignorar este tipo de errores no debería tener consecuencias inmediatas; las estructuras de datos centrales se prueban lo suficientemente bien como para sobrevivir fácilmente a esto.
  • Manejo de excepciones genérico: error grave atrapado, posiblemente falla en un momento posterior. Esto puede suceder raramente. Nunca lo hemos visto hasta ahora. El error se registra de todos modos y puede ser inevitable que se produzca un fallo. Esto es conceptualmente similar al primer caso, excepto que tenemos un seguimiento de pila. Y en la mayoría de los casos el usuario ni siquiera se dará cuenta.

En cuanto a los datos del experimento generados por el programa: un error grave provocaría, en el peor de los casos, que no se registraran datos. Es bastante improbable que se produzcan cambios sutiles que alteren ligeramente el resultado del experimento. E incluso en ese caso, si los resultados parecen dudosos, se registró el error; Todavía se puede descartar ese dato si es un valor atípico total.

Para resumir: Sí, me considero todavía al menos parcialmente cuerdo y no considero que una rutina de manejo de excepciones global que deja el programa en ejecución sea necesariamente totalmente malvada. Como ya se ha dicho dos veces antes, esa decisión podría ser válida, dependiendo de la aplicación. En este caso se consideró una decisión válida y no una tontería total y absoluta. Para cualquier otra aplicación, esa decisión podría verse diferente. Pero, por favor, no me acuséis a mí ni a las otras personas que trabajaron en ese proyecto de potencialmente hacer estallar el mundo sólo porque estamos ignorando los errores.

Nota al margen: hay exactamente un usuario para esa aplicación. No es algo como Windows u Office que utilizan millones de personas, donde el costo de tener excepciones para el usuario ya sería muy diferente en primer lugar.

Joey avatar Apr 27 '09 18:04 Joey
Aceptado

Utilizar el Application.DispatcherUnhandledException Event. Consulte esta pregunta para obtener un resumen (consulte la respuesta de Drew Noakes ).

Tenga en cuenta que todavía habrá excepciones que impedirán una reanudación exitosa de su aplicación, como después de un desbordamiento de pila, memoria agotada o pérdida de conectividad de red mientras intenta guardar en la base de datos.

David Schmitt avatar Apr 27 '2009 11:04 David Schmitt

Código de ejemplo que utiliza NLog que detectará excepciones lanzadas desde todos los subprocesos en AppDomain , desde el subproceso del despachador de UI y desde las funciones asíncronas :

Aplicación.xaml.cs:

public partial class App : Application
{
    private static Logger _logger = LogManager.GetCurrentClassLogger();

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        SetupExceptionHandling();
    }

    private void SetupExceptionHandling()
    {
        AppDomain.CurrentDomain.UnhandledException += (s, e) =>
            LogUnhandledException((Exception)e.ExceptionObject, "AppDomain.CurrentDomain.UnhandledException");

        DispatcherUnhandledException += (s, e) =>
        {
            LogUnhandledException(e.Exception, "Application.Current.DispatcherUnhandledException");
            e.Handled = true;
        };

        TaskScheduler.UnobservedTaskException += (s, e) =>
        {
            LogUnhandledException(e.Exception, "TaskScheduler.UnobservedTaskException");
            e.SetObserved();
        };
    }

    private void LogUnhandledException(Exception exception, string source)
    {
        string message = $"Unhandled exception ({source})";
        try
        {
            System.Reflection.AssemblyName assemblyName = System.Reflection.Assembly.GetExecutingAssembly().GetName();
            message = string.Format("Unhandled exception in {0} v{1}", assemblyName.Name, assemblyName.Version);
        }
        catch (Exception ex)
        {
            _logger.Error(ex, "Exception in LogUnhandledException");
        }
        finally
        {
            _logger.Error(exception, message);
        }
    }
Huseyin Yagli avatar Oct 18 '2017 07:10 Huseyin Yagli

Evento AppDomain.UnhandledException

Este evento proporciona notificación de excepciones no detectadas. Permite que la aplicación registre información sobre la excepción antes de que el controlador predeterminado del sistema informe la excepción al usuario y finalice la aplicación.

   public App()
   {
      AppDomain currentDomain = AppDomain.CurrentDomain;
      currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);    
   }

   static void MyHandler(object sender, UnhandledExceptionEventArgs args) 
   {
      Exception e = (Exception) args.ExceptionObject;
      Console.WriteLine("MyHandler caught : " + e.Message);
      Console.WriteLine("Runtime terminating: {0}", args.IsTerminating);
   }

Si el evento UnhandledException se maneja en el dominio de aplicación predeterminado, se genera allí para cualquier excepción no controlada en cualquier subproceso, sin importar en qué dominio de aplicación se inició el subproceso. Si el subproceso se inició en un dominio de aplicación que tiene un controlador de eventos para UnhandledException, el evento se genera en ese dominio de aplicación. Si ese dominio de aplicación no es el dominio de aplicación predeterminado y también hay un controlador de eventos en el dominio de aplicación predeterminado, el evento se genera en ambos dominios de aplicación.

Por ejemplo, supongamos que un hilo comienza en el dominio de aplicación "AD1", llama a un método en el dominio de aplicación "AD2" y desde allí llama a un método en el dominio de aplicación "AD3", donde genera una excepción. El primer dominio de aplicación en el que se puede generar el evento UnhandledException es "AD1". Si ese dominio de aplicación no es el dominio de aplicación predeterminado, el evento también se puede generar en el dominio de aplicación predeterminado.

CharithJ avatar Jul 21 '2015 22:07 CharithJ