Cómo: Recibir notificaciones de excepciones de primera oportunidad

El evento FirstChanceException de la clase AppDomain permite recibir una notificación sobre una excepción que se produce antes de que el Common Language Runtime comience a buscar los controladores de excepciones.

El evento se genera en el nivel del dominio de aplicación. Un subproceso de ejecución puede atravesar varios dominios de aplicación, de modo que una excepción que no se controla en un dominio se puede controlar en otro. La notificación se produce en cada dominio de aplicación que ha agregado un controlador para el evento, hasta que un dominio de aplicación controle la excepción.

Los procedimientos y los ejemplos de este artículo muestran cómo recibir notificaciones de excepciones de primera oportunidad en un programa simple que tiene un dominio de aplicación y en un dominio de aplicación que se crea.

Para obtener un ejemplo más complejo que abarca varios dominios de aplicación, vea el ejemplo para el evento FirstChanceException.

Recibir notificaciones de primera oportunidad en el dominio de aplicación predeterminado

En el siguiente procedimiento, el punto de entrada de la aplicación, el método Main(), se ejecuta en el dominio de aplicación predeterminado.

Para mostrar notificaciones de primera oportunidad en el dominio de aplicación predeterminado

  1. Defina un controlador para el evento FirstChanceException mediante una función lambda y adjúntelo al evento. En este ejemplo, el controlador de eventos imprime el nombre del dominio de aplicación donde se controló el evento y la propiedad Message de la excepción.

    Imports System.Runtime.ExceptionServices
    
    Class Example
    
        Shared Sub Main()
    
            AddHandler AppDomain.CurrentDomain.FirstChanceException, 
                       Sub(source As Object, e As FirstChanceExceptionEventArgs)
                           Console.WriteLine("FirstChanceException event raised in {0}: {1}",
                                             AppDomain.CurrentDomain.FriendlyName, 
                                             e.Exception.Message)
                       End Sub
    
    using System;
    using System.Runtime.ExceptionServices;
    
    class Example
    {
        static void Main()
        {
            AppDomain.CurrentDomain.FirstChanceException += 
                (object source, FirstChanceExceptionEventArgs e) =>
                {
                    Console.WriteLine("FirstChanceException event raised in {0}: {1}",
                        AppDomain.CurrentDomain.FriendlyName, e.Exception.Message);
                };
    
  2. Produzca una excepción y detéctela. Antes de que el runtime encuentre el controlador de excepciones, se produce el evento FirstChanceException y se muestra un mensaje. Este mensaje va seguido del mensaje mostrado por el controlador de excepciones.

    Try
        Throw New ArgumentException("Thrown in " & AppDomain.CurrentDomain.FriendlyName)
    
    Catch ex As ArgumentException
    
        Console.WriteLine("ArgumentException caught in {0}: {1}", 
            AppDomain.CurrentDomain.FriendlyName, ex.Message)
    End Try
    
    try
    {
        throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName);
    }
    catch (ArgumentException ex)
    {
        Console.WriteLine("ArgumentException caught in {0}: {1}", 
            AppDomain.CurrentDomain.FriendlyName, ex.Message);
    }
    
  3. Inicie una excepción pero no la detecte. Antes de que el runtime busque un controlador de excepciones, se produce el evento FirstChanceException y se muestra un mensaje. No hay ningún controlador de excepciones, de modo que la aplicación finaliza.

            Throw New ArgumentException("Thrown in " & AppDomain.CurrentDomain.FriendlyName)
        End Sub
    End Class
    
            throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName);
        }
    }
    

    El código que se muestra en los tres primeros pasos de este procedimiento forma una aplicación de consola completa. La salida de la aplicación varía, dependiendo del nombre del archivo .exe, porque el nombre del dominio de aplicación predeterminado consta del nombre y de la extensión del archivo .exe. A continuación, se muestra la salida de este ejemplo.

    ' This example produces output similar to the following:
    '
    'FirstChanceException event raised in Example.exe: Thrown in Example.exe
    'ArgumentException caught in Example.exe: Thrown in Example.exe
    'FirstChanceException event raised in Example.exe: Thrown in Example.exe
    '
    'Unhandled Exception: System.ArgumentException: Thrown in Example.exe
    '   at Example.Main()
    
    /* This example produces output similar to the following:
    
    FirstChanceException event raised in Example.exe: Thrown in Example.exe
    ArgumentException caught in Example.exe: Thrown in Example.exe
    FirstChanceException event raised in Example.exe: Thrown in Example.exe
    
    Unhandled Exception: System.ArgumentException: Thrown in Example.exe
       at Example.Main()
     */
    

Recibir notificaciones de primera oportunidad en otro dominio de aplicación

Si su programa contiene más de un dominio de aplicación, puede elegir cuáles reciben notificaciones.

Para recibir notificaciones de excepción de primera oportunidad en un dominio de aplicación creado por usted

  1. Defina un controlador de eventos para el evento FirstChanceException. En este ejemplo se utiliza un método static (Shared en Visual Basic) que imprime el nombre del dominio de aplicación donde se controló el evento y la propiedad Message de la excepción.

    Shared Sub FirstChanceHandler(ByVal source As Object, 
                                  ByVal e As FirstChanceExceptionEventArgs)
    
        Console.WriteLine("FirstChanceException event raised in {0}: {1}",
            AppDomain.CurrentDomain.FriendlyName, e.Exception.Message)
    End Sub
    
    static void FirstChanceHandler(object source, FirstChanceExceptionEventArgs e)
    {
        Console.WriteLine("FirstChanceException event raised in {0}: {1}",
            AppDomain.CurrentDomain.FriendlyName, e.Exception.Message);
    }
    
  2. Cree un dominio de aplicación y agregue el controlador de eventos al evento FirstChanceException para ese dominio de aplicación. En este ejemplo, el dominio de aplicación se denomina AD1.

    Dim ad As AppDomain = AppDomain.CreateDomain("AD1")
    AddHandler ad.FirstChanceException, AddressOf FirstChanceHandler
    
    AppDomain ad = AppDomain.CreateDomain("AD1");
    ad.FirstChanceException += FirstChanceHandler;
    

    Puede controlar este evento en el dominio de aplicación predeterminado de la misma manera. Utilice la propiedad AppDomain.CurrentDomain static (Shared en Visual Basic) en Main() para obtener una referencia al dominio de aplicación predeterminado.

Para mostrar notificaciones de primera oportunidad en el dominio de aplicación

  1. Cree un objeto Worker en el dominio de aplicación creado en el procedimiento anterior. La clase Worker debe ser pública y debe derivar de MarshalByRefObject, como se muestra en el ejemplo completo al final de este artículo.

    Dim w As Worker = CType(ad.CreateInstanceAndUnwrap(
                                Assembly.GetExecutingAssembly().FullName, "Worker"),
                            Worker)
    
    Worker w = (Worker) ad.CreateInstanceAndUnwrap(
                            Assembly.GetExecutingAssembly().FullName, "Worker");
    
  2. Llame a un método del objeto Worker que produce una excepción. En este ejemplo, se llama dos veces al método Thrower. La primera vez, el argumento de método es true, que hace que el método detecte su propia excepción. La segunda, el argumento es false y el método Main() detecta la excepción en el dominio de aplicación predeterminado.

    ' The worker throws an exception and catches it.
    w.Thrower(true)
    
    Try
        ' The worker throws an exception and doesn't catch it.
        w.Thrower(false)
    
    Catch ex As ArgumentException
    
        Console.WriteLine("ArgumentException caught in {0}: {1}", 
            AppDomain.CurrentDomain.FriendlyName, ex.Message)
    End Try
    
    // The worker throws an exception and catches it.
    w.Thrower(true);
    
    try
    {
        // The worker throws an exception and doesn't catch it.
        w.Thrower(false);
    }
    catch (ArgumentException ex)
    {
        Console.WriteLine("ArgumentException caught in {0}: {1}", 
            AppDomain.CurrentDomain.FriendlyName, ex.Message);
    }
    
  3. Ponga código en el método Thrower para comprobar si controla su propia excepción.

    If catchException
    
        Try
            Throw New ArgumentException("Thrown in " & AppDomain.CurrentDomain.FriendlyName)
    
        Catch ex As ArgumentException
    
            Console.WriteLine("ArgumentException caught in {0}: {1}", 
                AppDomain.CurrentDomain.FriendlyName, ex.Message)
        End Try
    Else
    
        Throw New ArgumentException("Thrown in " & AppDomain.CurrentDomain.FriendlyName)
    End If
    
    if (catchException)
    {
        try
        {
            throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName);
        }
        catch (ArgumentException ex)
        {
            Console.WriteLine("ArgumentException caught in {0}: {1}", 
                AppDomain.CurrentDomain.FriendlyName, ex.Message);
        }
    }
    else
    {
        throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName);
    }
    

Ejemplo

En el siguiente ejemplo se crea un dominio de aplicación denominado AD1 y se agrega un controlador de eventos al evento FirstChanceException del dominio de aplicación. En el ejemplo se crea una instancia de la clase Worker en el dominio de aplicación y se llama a un método Thrower que produce una excepción ArgumentException. Dependiendo del valor de su argumento, el método detecta la excepción o no.

Cada vez que el método Thrower produce una excepción en AD1, se genera el evento FirstChanceException en AD1 y el controlador de eventos muestra un mensaje. Después, el motor en tiempo de ejecución busca un controlador de excepciones. En el primer caso, el controlador de excepciones se encuentra en AD1. En el segundo, la excepción no se controla en AD1 pero se detecta en el dominio de aplicación predeterminado.

NotaNota

El nombre del dominio de aplicación predeterminado es el mismo que el del ejecutable.

Si agrega un controlador para el evento FirstChanceException en el dominio de aplicación predeterminado, el evento se genera y controla antes de que el dominio de aplicación predeterminado controle la excepción. Para verlo, agregue el código de C# AppDomain.CurrentDomain.FirstChanceException += FirstChanceException; (en Visual Basic, AddHandler AppDomain.CurrentDomain.FirstChanceException, FirstChanceException) al comienzo de Main().

Imports System.Reflection
Imports System.Runtime.ExceptionServices

Class Example

    Shared Sub Main()

        ' To receive first chance notifications of exceptions in 
        ' an application domain, handle the FirstChanceException
        ' event in that application domain.
        Dim ad As AppDomain = AppDomain.CreateDomain("AD1")
        AddHandler ad.FirstChanceException, AddressOf FirstChanceHandler


        ' Create a worker object in the application domain.
        Dim w As Worker = CType(ad.CreateInstanceAndUnwrap(
                                    Assembly.GetExecutingAssembly().FullName, "Worker"),
                                Worker)

        ' The worker throws an exception and catches it.
        w.Thrower(true)

        Try
            ' The worker throws an exception and doesn't catch it.
            w.Thrower(false)

        Catch ex As ArgumentException

            Console.WriteLine("ArgumentException caught in {0}: {1}", 
                AppDomain.CurrentDomain.FriendlyName, ex.Message)
        End Try
    End Sub

    Shared Sub FirstChanceHandler(ByVal source As Object, 
                                  ByVal e As FirstChanceExceptionEventArgs)

        Console.WriteLine("FirstChanceException event raised in {0}: {1}",
            AppDomain.CurrentDomain.FriendlyName, e.Exception.Message)
    End Sub
End Class

Public Class Worker
    Inherits MarshalByRefObject

    Public Sub Thrower(ByVal catchException As Boolean)

        If catchException

            Try
                Throw New ArgumentException("Thrown in " & AppDomain.CurrentDomain.FriendlyName)

            Catch ex As ArgumentException

                Console.WriteLine("ArgumentException caught in {0}: {1}", 
                    AppDomain.CurrentDomain.FriendlyName, ex.Message)
            End Try
        Else

            Throw New ArgumentException("Thrown in " & AppDomain.CurrentDomain.FriendlyName)
        End If
    End Sub
End Class

' This example produces output similar to the following:
'
'FirstChanceException event raised in AD1: Thrown in AD1
'ArgumentException caught in AD1: Thrown in AD1
'FirstChanceException event raised in AD1: Thrown in AD1
'ArgumentException caught in Example.exe: Thrown in AD1
using System;
using System.Reflection;
using System.Runtime.ExceptionServices;

class Example
{
    static void Main()
    {
        // To receive first chance notifications of exceptions in 
        // an application domain, handle the FirstChanceException
        // event in that application domain.
        AppDomain ad = AppDomain.CreateDomain("AD1");
        ad.FirstChanceException += FirstChanceHandler;

        // Create a worker object in the application domain.
        Worker w = (Worker) ad.CreateInstanceAndUnwrap(
                                Assembly.GetExecutingAssembly().FullName, "Worker");

        // The worker throws an exception and catches it.
        w.Thrower(true);

        try
        {
            // The worker throws an exception and doesn't catch it.
            w.Thrower(false);
        }
        catch (ArgumentException ex)
        {
            Console.WriteLine("ArgumentException caught in {0}: {1}", 
                AppDomain.CurrentDomain.FriendlyName, ex.Message);
        }
    }

    static void FirstChanceHandler(object source, FirstChanceExceptionEventArgs e)
    {
        Console.WriteLine("FirstChanceException event raised in {0}: {1}",
            AppDomain.CurrentDomain.FriendlyName, e.Exception.Message);
    }
}

public class Worker : MarshalByRefObject
{
    public void Thrower(bool catchException)
    {
        if (catchException)
        {
            try
            {
                throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName);
            }
            catch (ArgumentException ex)
            {
                Console.WriteLine("ArgumentException caught in {0}: {1}", 
                    AppDomain.CurrentDomain.FriendlyName, ex.Message);
            }
        }
        else
        {
            throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName);
        }
    }
}

/* This example produces output similar to the following:

FirstChanceException event raised in AD1: Thrown in AD1
ArgumentException caught in AD1: Thrown in AD1
FirstChanceException event raised in AD1: Thrown in AD1
ArgumentException caught in Example.exe: Thrown in AD1
 */

Compilar el código

  • Este ejemplo es una aplicación de línea de comandos. Para compilarlo y ejecutarlo en Visual Studio 2010, agregue el código de C# Console.ReadLine(); (en Visual Basic, Console.ReadLine()) al final de Main() para impedir que la ventana de comandos se cierre antes de haber leído el resultado.

Vea también

Referencia

FirstChanceException