Como: Receber notificações de exceção de primeira tentativa
Observação
Este artigo é específico para aplicativos .NET Framework. Não se aplica a implementações mais recentes do .NET, incluindo o .NET 6 e versões posteriores.
O evento FirstChanceException da classe AppDomain permite que você receba uma notificação de que uma exceção foi lançada, antes de o Common Language Runtime começar a procurar por manipuladores de exceção.
O evento é gerado no nível de domínio do aplicativo. Um thread de execução pode passar por vários domínios de aplicativo, assim, uma exceção não tratada em um domínio de aplicativo poderia ser tratada em outro domínio de aplicativo. A notificação ocorre em cada domínio de aplicativo que tenha adicionado um manipulador para o evento, até que um domínio de aplicativo lide com a exceção.
Os procedimentos e os exemplos neste artigo mostram como receber notificações de exceções de primeira tentativa em um programa simples que tem um domínio de aplicativo, e em um domínio de aplicativo que você criar.
Para obter um exemplo mais complexo que abrange vários domínios de aplicativo, veja o exemplo para o evento FirstChanceException.
Receber notificações de exceção de primeira tentativa no Domínio do aplicativo padrão
No procedimento a seguir, o ponto de entrada para o aplicativo, o método Main()
, é executado no domínio do aplicativo padrão.
Para demonstrar notificações de exceção de primeira tentativa no domínio do aplicativo padrão
Defina um manipulador de eventos para o evento FirstChanceException usando uma função lambda e anexe-o ao evento. Neste exemplo, o manipulador de eventos imprime o nome do domínio do aplicativo no qual o evento foi tratado e a propriedade Message da exceção.
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
Gere uma exceção e capture-a. Antes de o runtime localizar o manipulador de exceção, o evento FirstChanceException é gerado e exibe uma mensagem. Essa mensagem é seguida pela mensagem exibida pelo manipulador de exceção.
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
Gere uma exceção, mas não a capture. Antes de o runtime procurar o manipulador de exceção, o evento FirstChanceException é gerado e exibe uma mensagem. Não há um manipulador de exceções, portanto, o aplicativo será encerrado.
throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName); } }
Throw New ArgumentException("Thrown in " & AppDomain.CurrentDomain.FriendlyName) End Sub End Class
O código que é mostrado nas três primeiras etapas deste procedimento forma um aplicativo de console completo. A saída do aplicativo varia, dependendo do nome do arquivo .exe, pois o nome do domínio do aplicativo padrão é formado pelo nome e pela extensão do arquivo .exe. Veja o seguinte para a saída de exemplo.
/* 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()
Receber notificações de exceção de primeira tentativa em outro Domínio do aplicativo
Se seu programa contiver mais de um domínio de aplicativo, escolha quais domínios de aplicativo recebem notificações.
Para receber notificações de exceção de primeira tentativa em outro Domínio do aplicativo criado por você
Defina um manipulador de eventos para o evento FirstChanceException. Este exemplo usa um método
static
(métodoShared
no Visual Basic) que imprime o nome do domínio do aplicativo no qual o evento foi tratado e a propriedade Message da exceção.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
Crie um domínio do aplicativo e adicione o manipulador de eventos ao evento FirstChanceException para esse domínio do aplicativo. Neste exemplo, o domínio de aplicativo é chamado
AD1
.AppDomain ad = AppDomain.CreateDomain("AD1"); ad.FirstChanceException += FirstChanceHandler;
Dim ad As AppDomain = AppDomain.CreateDomain("AD1") AddHandler ad.FirstChanceException, AddressOf FirstChanceHandler
Você pode manipular esse evento no domínio do aplicativo padrão da mesma maneira. Use a propriedade AppDomain.CurrentDomain
static
(Shared
no Visual Basic) noMain()
para obter uma referência para o domínio do aplicativo padrão.
Para demonstrar notificações de exceção de primeira tentativa no domínio do aplicativo
Crie um objeto
Worker
no domínio do aplicativo que você criou no procedimento anterior. A classeWorker
deve ser pública e deve derivar de MarshalByRefObject, conforme mostra o exemplo completo no final deste artigo.Worker w = (Worker) ad.CreateInstanceAndUnwrap( typeof(Worker).Assembly.FullName, "Worker");
Dim w As Worker = CType(ad.CreateInstanceAndUnwrap( GetType(Worker).Assembly.FullName, "Worker"), Worker)
Chame um método do objeto
Worker
que gera uma exceção. Nesse exemplo, o métodoThrower
é chamado duas vezes. Na primeira vez, o argumento do método étrue
, que faz com que o método capture sua própria exceção. Na segunda vez, o argumento éfalse
, e o métodoMain()
captura a exceção no domínio de aplicativo padrão.// 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 o código no método
Thrower
para controlar se o método lida com sua própria exceção.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
Exemplo
O exemplo a seguir cria um domínio do aplicativo chamado AD1
e adiciona o manipulador de eventos ao evento FirstChanceException do domínio do aplicativo. O exemplo cria uma instância da classe Worker
no domínio do aplicativo e chama um método chamado Thrower
, que gera uma ArgumentException. Dependendo do valor do argumento, o método captura a exceção ou não consegue lidar com ela.
Cada vez que o método Thrower
gera uma exceção no AD1
, o evento FirstChanceException é gerado no AD1
e o manipulador de eventos exibe uma mensagem. Em seguida, o runtime procura um manipulador de exceção. No primeiro caso, o manipulador de exceção é encontrado em AD1
. No segundo caso, a exceção é tratada no AD1
e, em vez disso, é capturada no domínio do aplicativo padrão.
Observação
O nome do domínio do aplicativo padrão é igual ao nome do executável.
Se você adicionar um manipulador ao evento FirstChanceException para o domínio do aplicativo padrão, o evento será disparado e tratado antes de o domínio de aplicativo padrão lidar com a exceção. Para ver isso, adicione o código C# AppDomain.CurrentDomain.FirstChanceException += FirstChanceException;
(no Visual Basic, AddHandler AppDomain.CurrentDomain.FirstChanceException, FirstChanceException
) no início 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