Partilhar via


Como: Receber notificações de exceção de primeira chance

Nota

Este artigo é específico do .NET Framework. Ele não se aplica a implementações mais recentes do .NET, incluindo o .NET 6 e versões posteriores.

O FirstChanceException evento da classe permite que você receba uma notificação de que uma exceção foi lançada, antes que o common language runtime tenha começado a procurar manipuladores de AppDomain exceção.

O evento é gerado no nível do domínio do aplicativo. Um thread de execução pode passar por vários domínios de aplicativo, portanto, uma exceção que não é tratada em um domínio de aplicativo pode ser tratada em outro domínio de aplicativo. A notificação ocorre em cada domínio de aplicativo que adicionou um manipulador para o evento, até que um domínio de aplicativo manipule a exceção.

Os procedimentos e exemplos neste artigo mostram como receber notificações de exceção de primeira chance em um programa simples que tem um domínio de aplicativo e em um domínio de aplicativo que você cria.

Para obter um exemplo mais complexo que abrange vários domínios de aplicativo, consulte o exemplo para o FirstChanceException evento.

Recebendo notificações de exceção de primeira chance no domínio do aplicativo padrão

No procedimento a seguir, o ponto de entrada para o aplicativo, o Main() método, é executado no domínio de aplicativo padrão.

Para demonstrar notificações de exceção de primeira chance no domínio de aplicativo padrão

  1. Defina um manipulador de eventos para o FirstChanceException evento, usando uma função lambda, e anexe-o ao evento. Neste exemplo, o manipulador de eventos imprime o nome do domínio do aplicativo onde o evento foi manipulado e a propriedade da Message 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
    
  2. Lance uma exceção e pegue-a. Antes que o tempo de execução localize o manipulador de exceção, o FirstChanceException evento é gerado e exibe uma mensagem. Essa mensagem é seguida pela mensagem exibida pelo manipulador de exceções.

    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
    
  3. Lance uma exceção, mas não a pegue. Antes que o tempo de execução procure um manipulador de exceção, o FirstChanceException evento é gerado e exibe uma mensagem. Não há manipulador de exceção, portanto, o aplicativo é encerrado.

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

    O código 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, porque o nome do domínio do aplicativo padrão consiste no nome e na extensão do arquivo .exe. Consulte o seguinte para obter 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()
    

Recebendo notificações de exceção de primeira chance em outro domínio de aplicativo

Se o seu programa contiver mais de um domínio de aplicativo, você poderá escolher quais domínios de aplicativo receberão notificações.

Para receber notificações de exceção de primeira chance em um domínio de aplicativo criado por você

  1. Defina um manipulador de eventos para o FirstChanceException evento. Este exemplo usa um static método (Shared método no Visual Basic) que imprime o nome do domínio do aplicativo onde o evento foi manipulado e a propriedade da Message 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
    
  2. Crie um domínio de aplicativo e adicione o manipulador de eventos ao FirstChanceException evento desse domínio de aplicativo. Neste exemplo, o domínio do 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 static propriedade (Shared no Visual Basic) AppDomain.CurrentDomain para Main() obter uma referência ao domínio de aplicativo padrão.

Para demonstrar notificações de exceção de primeira chance no domínio do aplicativo

  1. Crie um Worker objeto no domínio do aplicativo que você criou no procedimento anterior. A Worker classe deve ser pública e derivar de MarshalByRefObject, como mostrado no 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)
    
  2. Chame Worker um método do objeto que lança uma exceção. Neste exemplo, o Thrower método é chamado duas vezes. Na primeira vez, o argumento do método é true, o que faz com que o método capture sua própria exceção. Na segunda vez, o argumento é false, e o Main() método 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
    
  3. Coloque o Thrower código no método para controlar se o método manipula 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 de aplicativo chamado AD1 e adiciona um manipulador de eventos ao evento do domínio do FirstChanceException aplicativo. O exemplo cria uma instância da Worker classe no domínio do aplicativo e chama um método chamado Thrower que lança um ArgumentExceptionarquivo . Dependendo do valor de seu argumento, o método captura a exceção ou não consegue manipulá-la.

Cada vez que o Thrower método lança uma exceção no AD1, o FirstChanceException evento é gerado em AD1, e o manipulador de eventos exibe uma mensagem. Em seguida, o tempo de execução procura um manipulador de exceções. No primeiro caso, o manipulador de exceção é encontrado em AD1. No segundo caso, a exceção não é tratada no AD1, e em vez disso é capturada no domínio de aplicativo padrão.

Nota

O nome do domínio do aplicativo padrão é o mesmo que o nome do executável.

Se você adicionar um manipulador para o FirstChanceException evento ao domínio de aplicativo padrão, o evento será gerado e manipulado antes que o domínio de aplicativo padrão manipule a exceção. Para ver isso, adicione o código AppDomain.CurrentDomain.FirstChanceException += FirstChanceException; C# (em 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

Consulte também