Freigeben über


Gewusst wie: Empfangen von Ausnahmebenachrichtigungen (erste Chance)

Sie erhalten vom FirstChanceException-Ereignis der AppDomain-Klasse eine Benachrichtigung, dass eine Ausnahme ausgelöst wurde, bevor von der Common Language Runtime die Suche nach Ausnahmehandlern gestartet wurde.

Das Ereignis wird auf der Ebene der Anwendungsdomäne ausgelöst. Ein Ausführungsthread kann mehrere Anwendungsdomänen durchlaufen, damit eine Ausnahme, die in einer Anwendungsdomäne nicht behandelt wurde, in einer anderen Anwendungsdomäne behandelt werden kann. Die Benachrichtigung wird so lange in den Anwendungsdomänen mit einem Handler für das Ereignis ausgegeben, bis die Ausnahme von einer Anwendungsdomäne behandelt wird.

In den Prozeduren und den Beispielen in diesem Artikel wird veranschaulicht, wie Ausnahmebenachrichtigungen (erste Chance) in einem einfachen Programm, das eine Anwendungsdomäne aufweist, und in einer vom Benutzer erstellten Anwendungsdomäne empfangen werden.

Ein komplexeres Beispiel, das mehrere Anwendungsdomänen umfasst, finden Sie im Beispiel für das FirstChanceException-Ereignis.

Empfangen von Ausnahmebenachrichtigungen (erste Chance) in der Standardanwendungsdomäne

Im folgenden Verfahren (dem Einstiegspunkt für die Anwendung) wird die Main()-Methode in der Standardanwendungsdomäne ausgeführt.

So werden Ausnahmebenachrichtigungen (erste Chance) in der Standardanwendungsdomäne dargestellt

  1. Definieren Sie einen Ereignishandler mit einer Lambda-Funktion für das FirstChanceException-Ereignis, und fügen Sie ihn an das Ereignis an. In diesem Beispiel gibt der Ereignishandler den Namen der Anwendungsdomäne, in der das Ereignis behandelt wurde, und die Message-Eigenschaft der Ausnahme aus.

    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. Lösen Sie eine Ausnahme aus, und fangen Sie sie ab. Bevor der Ausnahmehandler von der Runtime gefunden wird, wird das FirstChanceException-Ereignis ausgelöst und eine Meldung angezeigt. Dieser Meldung folgt die vom Ausnahmehandler angezeigte Meldung.

    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. Lösen Sie eine Ausnahme aus, fangen Sie sie aber nicht ab. Bevor der Ausnahmehandler von der Runtime gesucht wird, wird das FirstChanceException-Ereignis ausgelöst und eine Meldung angezeigt. Es ist kein Ausnahmehandler vorhanden. Die Anwendung wird beendet.

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

    Der Code in den ersten drei Schritten dieses Verfahrens bildet eine vollständige Konsolenanwendung. Die Ausgabe der Anwendung variiert abhängig vom Namen der EXE-Datei, da sich der Name der Standardanwendungsdomäne aus dem Namen und der Erweiterung der EXE-Datei zusammensetzt. Im Folgenden sehen Sie ein Beispiel für die Ausgabe.

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

Empfangen von Ausnahmebenachrichtigungen (erste Chance) in einer anderen Anwendungsdomäne

Wenn das Programm mehr als eine Anwendungsdomäne enthält, können Sie auswählen, welche Anwendungsdomänen Benachrichtigungen empfangen sollen.

So empfangen Sie Ausnahmebenachrichtigungen (erste Chance) in einer von Ihnen erstellten Anwendungsdomäne

  1. Definieren Sie einen Ereignishandler für das FirstChanceException-Ereignis. In diesem Beispiel wird eine static-Methode verwendet (Shared-Methode in Visual Basic), die den Namen der Anwendungsdomäne, in der das Ereignis behandelt wurde, sowie die Message-Eigenschaft der Ausnahme druckt.

    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. Erstellen Sie eine Anwendungsdomäne, und fügen Sie dem FirstChanceException-Ereignis den Ereignishandler für diese Anwendungsdomäne hinzu. In diesem Beispiel trägt die Anwendungsdomäne die Bezeichnung AD1.

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

    Sie können dieses Ereignis in der Standardanwendungsdomäne auf dieselbe Weise behandeln. Verwenden Sie die static (Shared in Visual Basic) AppDomain.CurrentDomain-Eigenschaft in Main(), um einen Verweis auf die Standardanwendungsdomäne abzurufen.

So werden Ausnahmebenachrichtigungen (erste Chance) in der Anwendungsdomäne dargestellt

  1. Erstellen Sie ein Worker-Objekt in der Anwendungsdomäne, die Sie im vorherigen Verfahren erstellt haben. Die Worker-Klasse muss öffentlich sein und sich von MarshalByRefObject ableiten, wie im vollständigen Beispiel am Ende dieses Artikels gezeigt.

    Dim w As Worker = CType(ad.CreateInstanceAndUnwrap(
                                Assembly.GetExecutingAssembly().FullName, "Worker"),
                            Worker)
    
    Worker w = (Worker) ad.CreateInstanceAndUnwrap(
                            Assembly.GetExecutingAssembly().FullName, "Worker");
    
  2. Rufen Sie eine Methode des Worker-Objekts auf, die eine Ausnahme auslöst. In diesem Beispiel wird die Thrower-Methode zweimal aufgerufen. Beim ersten Mal ist das Methodenargument auf true festgelegt, wodurch von der Methode die eigene Ausnahme abgefangen wird. Beim zweiten Mal ist das Argument auf false festgelegt, und von der Main()-Methode wird die Ausnahme in der Standardanwendungsdomäne abgefangen.

    ' 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. Platzieren Sie Code in der Thrower-Methode, um zu steuern, ob von der Methode eine eigene Ausnahme behandelt werden soll.

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

Beispiel

Im folgenden Beispiel wird eine Anwendungsdomäne mit der Bezeichnung AD1 erstellt und dem FirstChanceException-Ereignis der Anwendungsdomäne ein Ereignishandler hinzugefügt. Zusätzlich wird eine Instanz der Worker-Klasse in der Anwendungsdomäne erstellt und eine Thrower-Methode aufgerufen, von der eine ArgumentException ausgelöst wird. Je nach Wert des Arguments wird von der Methode die Ausnahme entweder abgefangen oder nicht behandelt.

Jedes Mal, wenn von der Thrower-Methode eine Ausnahme in AD1 ausgelöst wird, wird das FirstChanceException-Ereignis in AD1 ausgelöst, und vom Ereignishandler wird eine Meldung angezeigt. Anschließend wird von der Laufzeit nach einem Ausnahmehandler gesucht. Im ersten Fall wird der Ausnahmehandler in AD1 gefunden. Im zweiten Fall wird die Ausnahme in AD1 nicht behandelt und stattdessen in der Standardanwendungsdomäne abgefangen.

HinweisHinweis

Der Name der Standardanwendungsdomäne entspricht dem Namen der EXE-Datei.

Wenn Sie der Standardanwendungsdomäne einen Handler für das FirstChanceException-Ereignis hinzufügen, wird das Ereignis ausgelöst und behandelt, bevor die Ausnahme von der Standardanwendungsdomäne behandelt wird. Fügen Sie den C#-Code AppDomain.CurrentDomain.FirstChanceException += FirstChanceException; (in Visual Basic AddHandler AppDomain.CurrentDomain.FirstChanceException, FirstChanceExceptio) am Anfang von Main() ein, um diesen Effekt zu erzielen.

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

Kompilieren des Codes

  • Dieses Beispiel ist eine Befehlszeilenanwendung. Zum Kompilieren und Ausführen dieses Codes in Visual Studio 2010 fügen Sie den C#-Code am Ende von Console.ReadLine();Main()(in Visual Basic Console.ReadLine()) ein. So wird verhindert, dass das Befehlsfenster geschlossen wird, bevor Sie die Ausgabe lesen können.

Siehe auch

Referenz

FirstChanceException