Partager via


Comment : recevoir des notifications des exceptions de première chance

L'événement FirstChanceException de la classe AppDomain vous permet de recevoir la notification qu'une exception a été levée, avant que le Common Language Runtime n'ait commencé à rechercher des gestionnaires d'exceptions.

L'événement est déclenché au niveau du domaine d'application. Un thread d'exécution peut traverser plusieurs domaines d'application, donc une exception qui n'est pas gérée dans un domaine d'application pourrait être contrôlée dans un autre domaine d'application. La notification se produit dans chaque domaine d'application qui a ajouté un gestionnaire pour l'événement, jusqu'à ce qu'un domaine d'application gère l'exception.

Les procédures et exemples dans cet article indiquent comment recevoir des notifications des exceptions de première chance dans un programme simple qui a un domaine d'application, et dans un domaine d'application que vous créez.

Pour obtenir un exemple plus complexe qui couvre plusieurs domaines d'application, consultez l'exemple pour l'événement FirstChanceException.

Réception de notifications des exceptions de première chance dans le domaine d'application par défaut

Dans la procédure suivante, le point d'entrée de l'application (la méthode Main()) est exécutée dans le domaine d'application par défaut.

Pour illustrer des notifications des exceptions de première chance dans le domaine d'application par défaut

  1. Définissez un gestionnaire d'événements pour l'événement FirstChanceException, à l'aide d'une fonction lambda et attachez-le à l'événement. Dans cet exemple, le gestionnaire d'événements imprime le nom du domaine d'application dans lequel l'événement a été géré ainsi que la propriété Message de l'exception.

    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. Levez une exception et interceptez-la. Avant que l'exécution ne trouve le gestionnaire d'exceptions, l'événement FirstChanceException est déclenché et affiche un message. Ce message est suivi par le message affiché par le gestionnaire d'exceptions.

    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. Levez une exception mais ne l'interceptez pas. Avant que le runtime ne recherche le gestionnaire d'exceptions, l'événement FirstChanceException est déclenché et affiche un message. Il n'y a aucun gestionnaire d'exceptions, donc l'application s'arrête.

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

    Le code affiché dans les trois premières étapes de cette procédure forme une application console complète. La sortie de l'application varie en fonction du nom du fichier .exe car le nom du domaine d'application par défaut se compose du nom et de l'extension du fichier .exe. Consultez l'exemple de sortie suivant.

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

Réception de notifications des exceptions de première chance dans un autre domaine d'application

Si votre programme contient plusieurs domaines d'application, vous pouvez choisir les domaines d'application qui reçoivent des notifications.

Pour recevoir des notifications des exceptions de première chance dans un domaine d'application que vous créez

  1. Définissez un gestionnaire d'événements pour l'événement FirstChanceException. Cet exemple utilise une méthode static (méthodeShared en Visual Basic) qui imprime le nom du domaine d'application où l'événement a été contrôlé ainsi que la propriété Message de l'exception.

    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. Créez un domaine d'application et ajoutez le gestionnaire d'événements à l'événement FirstChanceException pour ce domaine d'application. Dans cet exemple, le domaine d'application est nommé AD1.

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

    Vous pouvez gérer de la même façon cet événement dans le domaine d'application par défaut. Utilisez le static (Shared en Visual Basic) de la propriété AppDomain.CurrentDomain dans Main() pour obtenir une référence pour le domaine d'application par défaut.

Pour illustrer des notifications des exceptions de première chance dans le domaine d'application

  1. Créez un objet Worker dans le domaine d'application que vous avez créé dans la procédure précédente. La classe Worker doit être publique et doit dériver de MarshalByRefObject, comme indiqué dans l'exemple complet à la fin de cet article.

    Dim w As Worker = CType(ad.CreateInstanceAndUnwrap(
                                Assembly.GetExecutingAssembly().FullName, "Worker"),
                            Worker)
    
    Worker w = (Worker) ad.CreateInstanceAndUnwrap(
                            Assembly.GetExecutingAssembly().FullName, "Worker");
    
  2. Appelez une méthode de l'objet Worker qui lève une exception. Dans cet exemple, la méthode Thrower est appelée deux fois. La première fois, l'argument de méthode est true, la méthode intercepte donc sa propre exception. La deuxième fois, l'argument est false, et la méthode Main() intercepte l'exception dans le domaine d'application par défaut.

    ' 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. Placez le code dans la méthode Thrower à contrôler si la méthode gère sa propre exception.

    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);
    }
    

Exemple

L'exemple suivant crée un domaine d'application nommé AD1 et ajoute un gestionnaire d'événements à l'événement FirstChanceException du domaine d'application. L'exemple crée une instance de la classe Worker dans le nouveau domaine d'application et appelle une méthode nommée Thrower qui lève une ArgumentException. Selon la valeur de son argument, la méthode intercepte l'exception ou ne parvient pas à la gérer.

Chaque fois que la méthode Thrower lève une exception dans AD1, l'événement FirstChanceException est déclenché dans AD1, et le gestionnaire d'événements affiche un message. Le runtime recherche ensuite un gestionnaire d'exceptions. Dans le premier cas, le gestionnaire d'exceptions est recherché dans AD1. Dans le deuxième cas, l'exception n'est pas gérée dans AD1, et est interceptée à la place dans le domaine d'application par défaut.

RemarqueRemarque

Le nom du domaine d'application par défaut est le même que celui du fichier exécutable.

Si vous ajoutez un gestionnaire pour l'événement FirstChanceException au domaine d'application par défaut, l'événement est déclenché et géré avant que le domaine d'application par défaut ne gère l'exception. Pour afficher cela, ajoutez le code C# AppDomain.CurrentDomain.FirstChanceException += FirstChanceException; (en Visual Basic, AddHandler AppDomain.CurrentDomain.FirstChanceException, FirstChanceException) au début 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
 */

Compilation du code

  • Cet exemple est une application en ligne de commande. Pour compiler et exécuter ce code en Visual Studio 2010, ajoutez le code C# Console.ReadLine(); (en Visual Basic, Console.ReadLine()) à la fin de Main(), afin d'empêcher la fermeture de la fenêtre de commande pour pouvoir lire la sortie.

Voir aussi

Référence

FirstChanceException