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 cominci a cercare gestori di eccezioni.

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

Le procedure e gli esempi in questo articolo mostrano come ricevere notifiche di eccezioni first-chance in un programma semplice che presenta un solo dominio applicazione e in un dominio applicazione che si crea.

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

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

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

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

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

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

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

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

    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 applicazione predefinito è costituito dal nome e dall'estensione del file exe. Di seguito viene riportato 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 applicazione

Se il programma contiene più domini applicazione, è possibile scegliere quali domini applicazione riceveranno le notifiche.

Per ricevere notifiche di eccezioni first-chance in un dominio applicazione che si crea

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

    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);
    }
    
  2. Creare un dominio applicazione e aggiungere il gestore eventi all'evento FirstChanceException relativo a tale dominio applicazione. In questo esempio il dominio applicazione è denominato AD1.

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

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

Per visualizzare notifiche di eccezioni first-chance nel dominio applicazione

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

    Dim w As Worker = CType(ad.CreateInstanceAndUnwrap(
                                Assembly.GetExecutingAssembly().FullName, "Worker"),
                            Worker)
    
    Worker w = (Worker) ad.CreateInstanceAndUnwrap(
                            Assembly.GetExecutingAssembly().FullName, "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, l'argomento del metodo è true. Ciò fa in modo che il metodo rilevi la propria eccezione. La seconda volta, l'argomento è false e il metodo Main() rileva l'eccezione nel dominio 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 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);
    }
    
  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 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);
    }
    

Esempio

Nell'esempio seguente viene creato un dominio applicazione denominato AD1 e viene aggiunto un gestore eventi all'evento FirstChanceException del dominio applicazione. Nell'esempio viene creata un'istanza della classe Worker nel dominio applicazione e viene chiamato un metodo denominato Thrower che genera un oggetto 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, l'evento FirstChanceException viene generato in AD1 e il gestore eventi visualizza un messaggio. Quindi, il runtime cerca 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 applicazione predefinito.

NotaNota

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

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

Compilazione del codice

  • Questo esempio è un'applicazione della riga di comando. Per compilare ed eseguire questo codice in Visual Studio 2010, aggiungere il codice C# Console.ReadLine(); (in Visual Basic Console.ReadLine()) alla fine di Main() per impedire la chiusura della finestra di comando prima che sia possibile leggere l'output.

Vedere anche

Riferimenti

FirstChanceException