Procedimiento para recibir notificaciones de excepciones de primera oportunidad
Nota:
Este artículo es específico de .NET Framework. No se aplica a implementaciones más recientes de .NET, incluido .NET 6 y versiones posteriores.
El evento FirstChanceException de la clase AppDomain permite recibir una notificación de que se ha producido una excepción antes de que Common Language Runtime empiece a buscar controladores de excepciones.
El evento se genera en el nivel de dominio de aplicación. Un subproceso de ejecución puede pasar a través de varios dominios de aplicación, así que una excepción no controlada en un dominio de aplicación podría controlarse en otro. La notificación se produce en cada dominio de aplicación que haya 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 primera excepción en un programa sencillo con un dominio de aplicación y en un dominio de aplicación que cree.
Para ver un ejemplo más complejo que abarca varios dominios de aplicación, vaya al ejemplo del evento FirstChanceException.
Recepción de notificaciones de primera excepción 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 excepción en el dominio de aplicación predeterminado
Defina un controlador de eventos 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 ha controlado el evento y la propiedad Message de la excepción.
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); };
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
Inicie una excepción y captúrela. Antes de que el runtime busque el controlador de excepciones, se genera el evento FirstChanceException y se muestra un mensaje. Este mensaje va seguido del que muestra el controlador de excepciones.
try { throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName); } catch (ArgumentException ex) { Console.WriteLine("ArgumentException caught in {0}: {1}", AppDomain.CurrentDomain.FriendlyName, ex.Message); }
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
Inicie una excepción, pero no la capture. Antes de que el runtime busque un controlador de excepciones, se genera el evento FirstChanceException y se muestra un mensaje. No hay ningún controlador de excepciones, por lo que la aplicación finaliza.
throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName); } }
Throw New ArgumentException("Thrown in " & AppDomain.CurrentDomain.FriendlyName) End Sub End Class
El código que se muestra en los tres primeros pasos de este procedimiento forma una aplicación de consola completa. El resultado de la aplicación varía según el nombre del archivo .exe, porque el nombre del dominio de aplicación predeterminado consta del nombre y la extensión del archivo .exe. Vea el resultado del ejemplo siguiente.
/* 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()
Recepción de notificaciones de primera excepción en otro dominio de aplicación
Si el programa contiene más de un dominio de aplicación, puede elegir cuáles reciben notificaciones.
Para recibir notificaciones de primera excepción en un dominio de aplicación que cree
Defina un controlador de eventos para el evento FirstChanceException. En este ejemplo se usa un método
static
(Shared
en Visual Basic) que imprime el nombre del dominio de aplicación donde se ha controlado el evento y la propiedad Message de la excepción.static void FirstChanceHandler(object source, FirstChanceExceptionEventArgs e) { Console.WriteLine("FirstChanceException event raised in {0}: {1}", AppDomain.CurrentDomain.FriendlyName, e.Exception.Message); }
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
Cree un dominio de aplicación y agregue el controlador de eventos al evento FirstChanceException de ese dominio de aplicación. En este ejemplo, el dominio de aplicación se denomina
AD1
.AppDomain ad = AppDomain.CreateDomain("AD1"); ad.FirstChanceException += FirstChanceHandler;
Dim ad As AppDomain = AppDomain.CreateDomain("AD1") AddHandler ad.FirstChanceException, AddressOf FirstChanceHandler
Puede controlar este evento en el dominio de aplicación predeterminado de la misma manera. Use la propiedad AppDomain.CurrentDomain
static
(Shared
en Visual Basic) enMain()
para obtener una referencia al dominio de aplicación predeterminado.
Para mostrar notificaciones de primera excepción en el dominio de aplicación
Cree un objeto
Worker
en el dominio de aplicación que ha creado en el procedimiento anterior. La claseWorker
debe ser pública y debe derivar de MarshalByRefObject, como se muestra en el ejemplo completo al final de este artículo.Worker w = (Worker) ad.CreateInstanceAndUnwrap( typeof(Worker).Assembly.FullName, "Worker");
Dim w As Worker = CType(ad.CreateInstanceAndUnwrap( GetType(Worker).Assembly.FullName, "Worker"), Worker)
Llame a un método del objeto
Worker
que inicia una excepción. En este ejemplo, se llama al métodoThrower
dos veces. La primera vez, el argumento del método estrue
, lo que hace que el método capture su propia excepción. La segunda vez, el argumento esfalse
y el métodoMain()
captura 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 (ArgumentException ex) { Console.WriteLine("ArgumentException caught in {0}: {1}", AppDomain.CurrentDomain.FriendlyName, ex.Message); }
' 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
Coloque código en el método
Thrower
para controlar si el método controla su propia excepción.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); }
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
Ejemplo
En el ejemplo siguiente 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 denominado Thrower
que inicia una ArgumentException. Según el valor de su argumento, el método captura la excepción o no la controla.
Cada vez que el método Thrower
inicia una excepción en AD1
, se genera el evento FirstChanceException en AD1
y el controlador de eventos muestra un mensaje. Luego el runtime busca un controlador de excepciones. En el primer caso, el controlador de excepciones se encuentra en AD1
. En el segundo caso, la excepción no se controla en AD1
y se captura en el dominio de aplicación predeterminado.
Nota
El nombre del dominio de aplicación predeterminado es el mismo que el nombre del ejecutable.
Si agrega un controlador para el evento FirstChanceException al dominio de aplicación predeterminado, el evento se genera y se 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 principio de Main()
.
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(
typeof(Worker).Assembly.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
*/
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(
GetType(Worker).Assembly.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