Procédure : recevoir des notifications des exceptions de première chance
Remarque
Cet article est spécifique au .NET Framework. Ceci ne s’applique pas aux implémentations plus récentes de .NET, y compris .NET 6 et ultérieur.
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. Étant donné qu’un thread d’exécution peut traverser plusieurs domaines d’application, une exception qui n’est pas gérée dans un domaine d’application pourrait être géré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 de 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()
) s’exécute dans le domaine d’application par défaut.
Pour illustrer les notifications des exceptions de première chance dans le domaine d’application par défaut
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 où l’événement a été géré, ainsi que la propriété Message de l’exception.
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
Levez une exception et interceptez-la. Avant que le runtime ne trouve le gestionnaire d’exceptions, l’événement FirstChanceException est déclenché et affiche un message. Ce message est suivi du message affiché par le gestionnaire d’exceptions.
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
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. Comme il n’y a aucun gestionnaire d’exceptions, l’application s’arrête.
throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName); } }
Throw New ArgumentException("Thrown in " & AppDomain.CurrentDomain.FriendlyName) End Sub End Class
Le code affiché aux 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. Vous trouverez ci-dessous un exemple de sortie.
/* 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 ceux qui reçoivent des notifications.
Pour recevoir des notifications des exceptions de première chance dans un domaine d’application que vous créez
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é géré, ainsi que la propriété Message de l’exception.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
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 se nomme
AD1
.AppDomain ad = AppDomain.CreateDomain("AD1"); ad.FirstChanceException += FirstChanceHandler;
Dim ad As AppDomain = AppDomain.CreateDomain("AD1") AddHandler ad.FirstChanceException, AddressOf FirstChanceHandler
Vous pouvez gérer cet événement dans le domaine d’application par défaut de la même façon. Utilisez la propriété
static
(Shared
en Visual Basic) AppDomain.CurrentDomain dansMain()
pour obtenir une référence au domaine d’application par défaut.
Pour illustrer les notifications des exceptions de première chance dans le domaine d’application
Créez un objet
Worker
dans le domaine d’application que vous avez créé lors de la procédure précédente. La classeWorker
doit être publique et doit dériver de MarshalByRefObject, comme indiqué dans l’exemple complet à la fin de cet article.Worker w = (Worker) ad.CreateInstanceAndUnwrap( typeof(Worker).Assembly.FullName, "Worker");
Dim w As Worker = CType(ad.CreateInstanceAndUnwrap( GetType(Worker).Assembly.FullName, "Worker"), Worker)
Appelez une méthode de l’objet
Worker
qui lève une exception. Dans cet exemple, la méthodeThrower
est appelée deux fois. La première fois, l’argument de méthode esttrue
. La méthode intercepte donc sa propre exception. La deuxième fois, l’argument estfalse
, et la méthodeMain()
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 (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
Placez le code dans la méthode
Thrower
pour contrôler si la méthode gère sa propre exception.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
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 domaine d’application et appelle une méthode nommée Thrower
qui lève une ArgumentException. En fonction de 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 trouvé dans AD1
. Dans le deuxième cas, l’exception n’est pas gérée dans AD1
; elle est interceptée dans le domaine d’application par défaut.
Notes
Le nom du domaine d’application par défaut est identique au nom de l’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()
.
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