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
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); };
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); }
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
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); }
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
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");
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); }
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.
Nota |
---|
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.