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
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); };
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); }
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
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); }
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
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");
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); }
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.
Remarque |
---|
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.