AppDomain.FirstChanceException Událost

Definice

Nastane při vyvolání výjimky ve spravovaném kódu před modul runtime vyhledá zásobník volání pro obslužnou rutinu výjimky v doméně aplikace.

public:
 event EventHandler<System::Runtime::ExceptionServices::FirstChanceExceptionEventArgs ^> ^ FirstChanceException;
public event EventHandler<System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs>? FirstChanceException;
public event EventHandler<System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs> FirstChanceException;
[add: System.Security.SecurityCritical]
[remove: System.Security.SecurityCritical]
public event EventHandler<System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs> FirstChanceException;
member this.FirstChanceException : EventHandler<System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs> 
[<add: System.Security.SecurityCritical>]
[<remove: System.Security.SecurityCritical>]
member this.FirstChanceException : EventHandler<System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs> 
Public Custom Event FirstChanceException As EventHandler(Of FirstChanceExceptionEventArgs) 

Event Type

Atributy

Příklady

Následující příklad vytvoří řadu domén aplikace s názvem AD0 prostřednictvím AD3s objektem Worker v každé doméně aplikace. Každý Worker objekt má odkaz na Worker objekt v další doméně aplikace s výjimkou Worker v poslední doméně aplikace. Událost se FirstChanceException zpracovává ve všech doménách aplikace s výjimkou AD1.

Poznámka

Kromě tohoto příkladu, který ukazuje první náhodná oznámení o výjimce ve více doménách aplikace, najdete jednoduché případy použití v tématu Postupy: Příjem First-Chance oznámení o výjimce.

Po vytvoření domén aplikace volá výchozí doména aplikace metodu TestException pro první doménu aplikace. Každý Worker objekt volá metodu TestException pro další doménu aplikace, dokud poslední Worker nevyvolá výjimku, která je zpracována nebo neošetřená. Aktuální vlákno tedy prochází všemi doménami aplikace a TestException je přidáno do zásobníku v každé doméně aplikace.

Když poslední Worker objekt zpracuje výjimku, FirstChanceException událost je vyvolána pouze v poslední doméně aplikace. Ostatní domény aplikace nikdy nemají šanci výjimku zpracovat, takže se událost nevyvolá.

Pokud poslední Worker objekt nezpracuje výjimku, FirstChanceException událost je vyvolána v každé doméně aplikace, která má obslužnou rutinu události. Po dokončení každé obslužné rutiny události se zásobník dále odvíjí, dokud se výjimka nezachytí výchozí doménou aplikace.

Poznámka

Pokud chcete zjistit, jak se zobrazení zásobníku zvětšuje, když je událost vyvolána blíž a blíž k výchozí doméně aplikace, změňte e.Exception.Message v obslužných FirstChanceHandler rutinách událostí na e.Exception . Všimněte si, že při zavolání TestException přes hranice domény aplikace se zobrazí dvakrát: jednou pro proxy server a jednou pro zástupnou proceduru.

using System;
using System.Reflection;
using System.Runtime.ExceptionServices;

class FirstChanceExceptionSnippet
{
    static void Main()
    {
        AppDomain.CurrentDomain.FirstChanceException += FirstChanceHandler;

        // Create a set of application domains, with a Worker object in each one.
        // Each Worker object creates the next application domain.
        AppDomain ad = AppDomain.CreateDomain("AD0");
        Worker w = (Worker) ad.CreateInstanceAndUnwrap(
                                typeof(Worker).Assembly.FullName, "Worker");
        w.Initialize(0, 3);

        Console.WriteLine("\r\nThe last application domain throws an exception and catches it:");
        Console.WriteLine();
        w.TestException(true);

        try
        {
            Console.WriteLine(
                "\r\nThe last application domain throws an exception and does not catch it:");
            Console.WriteLine();
            w.TestException(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
{
    private AppDomain ad = null;
    private Worker w = null;

    public void Initialize(int count, int max)
    {
        // Handle the FirstChanceException event in all application domains except
        // AD1.
        if (count != 1)
        {
            AppDomain.CurrentDomain.FirstChanceException += FirstChanceHandler;
        }

        // Create another application domain, until the maximum is reached.
        // Field w remains null in the last application domain, as a signal
        // to TestException().
        if (count < max)
        {
            int next = count + 1;
            ad = AppDomain.CreateDomain("AD" + next);
            w = (Worker) ad.CreateInstanceAndUnwrap(
                             typeof(Worker).Assembly.FullName, "Worker");
            w.Initialize(next, max);
        }
    }

    public void TestException(bool handled)
    {
        // As long as there is another application domain, call TestException() on
        // its Worker object. When the last application domain is reached, throw a
        // handled or unhandled exception.
        if (w != null)
        {
            w.TestException(handled);
        }
        else if (handled)
        {
            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);
        }
    }

    static void FirstChanceHandler(object source, FirstChanceExceptionEventArgs e)
    {
        Console.WriteLine("FirstChanceException event raised in {0}: {1}",
            AppDomain.CurrentDomain.FriendlyName, e.Exception.Message);
    }
}

/* This example produces output similar to the following:

The last application domain throws an exception and catches it:

FirstChanceException event raised in AD3: Thrown in AD3
ArgumentException caught in AD3: Thrown in AD3

The last application domain throws an exception and does not catch it:

FirstChanceException event raised in AD3: Thrown in AD3
FirstChanceException event raised in AD2: Thrown in AD3
FirstChanceException event raised in AD0: Thrown in AD3
FirstChanceException event raised in Example.exe: Thrown in AD3
ArgumentException caught in Example.exe: Thrown in AD3
 */
open System
open System.Runtime.ExceptionServices

let firstChanceHandler _ (e: FirstChanceExceptionEventArgs) =
    printfn $"FirstChanceException event raised in {AppDomain.CurrentDomain.FriendlyName}: {e.Exception.Message}"

type Worker() =
    inherit MarshalByRefObject()

    let mutable w = Unchecked.defaultof<Worker>

    member _.Initialize(count, max) =
        // Handle the FirstChanceException event in all application domains except
        // AD1.
        if count <> 1 then
            AppDomain.CurrentDomain.FirstChanceException.AddHandler firstChanceHandler

        // Create another application domain, until the maximum is reached.
        // Field w remains null in the last application domain, as a signal
        // to TestException().
        if count < max then
            let next = count + 1
            let ad = AppDomain.CreateDomain("AD" + string next)
            w <-
                ad.CreateInstanceAndUnwrap(typeof<Worker>.Assembly.FullName, "Worker") :?> Worker
            w.Initialize(next, max)

    member _.TestException(handled) =
        // As long as there is another application domain, call TestException() on
        // its Worker object. When the last application domain is reached, throw a
        // handled or unhandled exception.
        if isNull (box w) then
            w.TestException handled
        elif handled then
            try
                raise (ArgumentException $"Thrown in {AppDomain.CurrentDomain.FriendlyName}")
            with :? ArgumentException as ex ->
                printfn $"ArgumentException caught in {AppDomain.CurrentDomain.FriendlyName}: {ex.Message}"
        else
            raise (ArgumentException $"Thrown in {AppDomain.CurrentDomain.FriendlyName}")

AppDomain.CurrentDomain.FirstChanceException.AddHandler firstChanceHandler

// Create a set of application domains, with a Worker object in each one.
// Each Worker object creates the next application domain.
let ad = AppDomain.CreateDomain "AD0"
let w = ad.CreateInstanceAndUnwrap(typeof<Worker>.Assembly.FullName, "Worker") :?> Worker
w.Initialize(0, 3)

printfn "\nThe last application domain throws an exception and catches it:\n"
w.TestException true

try
    printfn "\nThe last application domain throws an exception and does not catch it:\n"
    w.TestException false
with :? ArgumentException as ex ->
    printfn"ArgumentException caught in {AppDomain.CurrentDomain.FriendlyName}: {ex.Message}"

(* This example produces output similar to the following:

The last application domain throws an exception and catches it:

FirstChanceException event raised in AD3: Thrown in AD3
ArgumentException caught in AD3: Thrown in AD3

The last application domain throws an exception and does not catch it:

FirstChanceException event raised in AD3: Thrown in AD3
FirstChanceException event raised in AD2: Thrown in AD3
FirstChanceException event raised in AD0: Thrown in AD3
FirstChanceException event raised in Example.exe: Thrown in AD3
ArgumentException caught in Example.exe: Thrown in AD3
 *)
Imports System.Reflection
Imports System.Runtime.ExceptionServices

Class Example

    Shared Sub Main()
    
        AddHandler AppDomain.CurrentDomain.FirstChanceException, AddressOf FirstChanceHandler

        ' Create a set of application domains, with a Worker object in each one.
        ' Each Worker object creates the next application domain.
        Dim ad As AppDomain = AppDomain.CreateDomain("AD0")
        Dim w As Worker = CType(ad.CreateInstanceAndUnwrap(
                                GetType(Worker).Assembly.FullName, "Worker"),
                                Worker)
        w.Initialize(0, 3)

        Console.WriteLine(vbCrLf & "The last application domain throws an exception and catches it:")
        Console.WriteLine()
        w.TestException(true)

        Try
            Console.WriteLine(vbCrLf & 
                "The last application domain throws an exception and does not catch it:")
            Console.WriteLine()
            w.TestException(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

    Private ad As AppDomain = Nothing
    Private w As Worker = Nothing

    Public Sub Initialize(ByVal count As Integer, ByVal max As Integer)
    
        ' Handle the FirstChanceException event in all application domains except
        ' AD1.
        If count <> 1
        
            AddHandler AppDomain.CurrentDomain.FirstChanceException, AddressOf FirstChanceHandler

        End If

        ' Create another application domain, until the maximum is reached.
        ' Field w remains Nothing in the last application domain, as a signal 
        ' to TestException(). 
        If count < max
            Dim nextAD As Integer = count + 1
            ad = AppDomain.CreateDomain("AD" & nextAD)
            w = CType(ad.CreateInstanceAndUnwrap(
                      GetType(Worker).Assembly.FullName, "Worker"),
                      Worker)
            w.Initialize(nextAD, max)
        End If
    End Sub

    Public Sub TestException(ByVal handled As Boolean)
    
        ' As long as there is another application domain, call TestException() on
        ' its Worker object. When the last application domain is reached, throw a
        ' handled or unhandled exception.
        If w IsNot Nothing
        
            w.TestException(handled)

        Else If handled
        
            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

    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

' This example produces output similar to the following:
'
'The last application domain throws an exception and catches it:
'
'FirstChanceException event raised in AD3: Thrown in AD3
'ArgumentException caught in AD3: Thrown in AD3
'
'The last application domain throws an exception and does not catch it:
'
'FirstChanceException event raised in AD3: Thrown in AD3
'FirstChanceException event raised in AD2: Thrown in AD3
'FirstChanceException event raised in AD0: Thrown in AD3
'FirstChanceException event raised in Example.exe: Thrown in AD3
'ArgumentException caught in Example.exe: Thrown in AD3

Poznámky

Tato událost je pouze oznámení. Zpracování této události nezpracuje výjimku ani nijak neovlivní následné zpracování výjimek. Po vyvolání události a vyvolání obslužných rutin událostí začne modul CLR (Common Language Runtime) hledat obslužnou rutinu výjimky. FirstChanceException poskytuje doméně aplikace první šanci prozkoumat jakoukoli spravovanou výjimku.

Událost je možné zpracovat pro doménu aplikace. Pokud vlákno prochází více domén aplikace při provádění volání, událost je vyvolána v každé doméně aplikace, která má zaregistrovanou obslužnou rutinu události, než CLR začne hledat odpovídající obslužnou rutinu výjimky v této doméně aplikace. Po zpracování události se provede hledání odpovídající obslužné rutiny výjimky v této doméně aplikace. Pokud se žádná nenajde, událost se vyvolá v další doméně aplikace.

Musíte zpracovat všechny výjimky, ke kterým dochází v obslužné rutině FirstChanceException události události. FirstChanceException V opačném případě je vyvolána rekurzivně. To může mít za následek přetečení zásobníku a ukončení aplikace. Doporučujeme implementovat obslužné rutiny událostí pro tuto událost jako oblasti omezeného spuštění (CER), aby výjimky související s infrastrukturou, jako je nedostatek paměti nebo přetečení zásobníku, během zpracování oznámení o výjimce neovlivňovaly virtuální počítač.

Tato událost není vyvolána pro výjimky, které indikují poškození stavu procesu, například narušení přístupu, pokud obslužná rutina události není kritická pro zabezpečení a má HandleProcessCorruptedStateExceptionsAttribute atribut .

Modul CLR (Common Language Runtime) během zpracování této události oznámení pozastaví přerušení vlákna.

Platí pro

Viz také