Procedura: ricevere notifiche di eccezioni first-chance

L'evento FirstChanceException della classe AppDomain consente di ricevere una notifica in cui si informa che è stata generata un'eccezione, prima che Common Language Runtime inizi a cercare gestori di eccezioni .

L'evento viene generato a livello di dominio dell'applicazione. Poiché un thread di esecuzione può passare attraverso più domini dell'applicazione, un'eccezione che non viene gestita in un dominio dell'applicazione può essere gestita in un altro dominio dell'applicazione. La notifica si verifica in ogni dominio dell'applicazione che ha aggiunto un gestore per l'evento fino a quando un dominio non gestisce l'eccezione.

Le procedure e gli esempi di questo articolo illustrano come ricevere notifiche di eccezioni first-chance in un programma semplice che include un solo dominio dell'applicazione e in un dominio dell'applicazione creato.

Per un esempio più complesso che riguarda più domini dell'applicazione, vedere l'esempio relativo all'evento FirstChanceException.

Ricezione di notifiche di eccezioni first-chance nel dominio dell'applicazione predefinito

Nella procedura seguente il punto di ingresso per l'applicazione, il metodo Main(), viene eseguito nel dominio dell'applicazione predefinito.

Per visualizzare notifiche di eccezioni first-chance nel dominio dell'applicazione predefinito

  1. Definire un gestore dell'evento per l'evento FirstChanceException usando una funzione lambda e collegarlo all'evento. In questo esempio il gestore dell'evento stampa il nome del dominio dell'applicazione in cui l'evento è stato gestito e la proprietà Message dell'eccezione.

    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. Generare un'eccezione e rilevarla. Prima che il runtime individui il gestore di eccezioni, viene generato l'evento FirstChanceException che visualizza un messaggio. Questo messaggio è seguito dal messaggio visualizzato dal gestore di eccezioni.

    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. Generare un'eccezione senza rilevarla. Prima che il runtime cerchi un gestore di eccezioni, viene generato l'evento FirstChanceException che visualizza un messaggio. Poiché non è presente alcun gestore di eccezioni, l'applicazione viene chiusa.

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

    Il codice visualizzato nei primi tre passaggi di questa procedura forma un'applicazione console completa. L'output dell'applicazione varia a seconda del nome del file con estensione exe, perché il nome del dominio dell'applicazione predefinito è costituito dal nome e dall'estensione del file exe. Di seguito è illustrato un output di esempio.

    /* 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()
    

Ricezione di notifiche di eccezioni first-chance in un altro dominio dell'applicazione

Se il programma contiene più domini di applicazione, è possibile specificare i domini di applicazione che ricevono le notifiche.

Per ricevere notifiche di eccezioni first-chance in un dominio dell'applicazione creato

  1. Definire un gestore dell'evento per l'evento FirstChanceException. Questo esempio usa un metodo static (Shared in Visual Basic) che stampa il nome del dominio dell'applicazione in cui l'evento viene gestito e la proprietà Message dell'eccezione.

    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. Creare un dominio dell'applicazione e aggiungere il gestore dell'evento all'evento FirstChanceException per il dominio dell'applicazione. In questo esempio il dominio dell'applicazione è denominato AD1.

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

    È possibile gestire questo evento nel dominio dell'applicazione predefinito nello stesso modo. Usare la proprietà static (Shared in Visual Basic) AppDomain.CurrentDomain in Main() per ottenere un riferimento al dominio dell'applicazione predefinito.

Per visualizzare notifiche di eccezioni first-chance nel dominio dell'applicazione

  1. Creare un oggetto Worker nel dominio dell'applicazione creato nella procedura precedente. La classe Worker deve essere pubblica e deve derivare da MarshalByRefObject, come illustrato nell'esempio completo alla fine di questo articolo.

    Worker w = (Worker) ad.CreateInstanceAndUnwrap(
                            typeof(Worker).Assembly.FullName, "Worker");
    
    Dim w As Worker = CType(ad.CreateInstanceAndUnwrap(
                                GetType(Worker).Assembly.FullName, "Worker"),
                            Worker)
    
  2. Chiamare un metodo dell'oggetto Worker che genera un'eccezione. In questo esempio il metodo Thrower viene chiamato due volte. La prima volta, poiché l'argomento del metodo è true, il metodo rileva la propria eccezione. La seconda volta, l'argomento è false e il metodo Main() rileva l'eccezione nel dominio dell'applicazione predefinito.

    // 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. Inserire codice nel metodo Thrower per controllare se il metodo gestisce la propria eccezione.

    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
    

Esempio

L'esempio seguente crea un dominio dell'applicazione denominato AD1 e aggiunge un gestore dell'evento all'evento FirstChanceException del dominio dell'applicazione. L'esempio crea un'istanza della classe Worker nel dominio dell'applicazione e chiama un metodo denominato Thrower che genera ArgumentException. A seconda del valore del proprio argomento, il metodo rileva l'eccezione o non riesce a gestirla.

Ogni volta che il metodo Thrower genera un'eccezione in AD1, viene generato l'evento FirstChanceException in AD1 e il gestore dell'evento visualizza un messaggio. Il runtime cerca quindi un gestore di eccezioni. Nel primo caso il gestore di eccezioni viene trovato in AD1. Nel secondo caso anziché essere gestita in AD1, l'eccezione viene rilevata nel dominio dell'applicazione predefinito.

Nota

Il nome del dominio dell'applicazione predefinito è uguale al nome dell'eseguibile.

Se si aggiunge un gestore per l'evento FirstChanceException al dominio dell'applicazione predefinito, l'evento viene generato e gestito prima che il dominio dell'applicazione predefinito gestisca l'eccezione. Per verificarlo, aggiungere il codice C# AppDomain.CurrentDomain.FirstChanceException += FirstChanceException; (in Visual Basic, AddHandler AppDomain.CurrentDomain.FirstChanceException, FirstChanceException) all'inizio di 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

Vedi anche