AppDomain.FirstChanceException Zdarzenie
Definicja
Ważne
Niektóre informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany przed wydaniem. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.
Występuje, gdy wyjątek jest zgłaszany w kodzie zarządzanym, zanim środowisko uruchomieniowe przeszukuje stos wywołań programu obsługi wyjątków w domenie aplikacji.
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)
Typ zdarzenia
- Atrybuty
Przykłady
W poniższym przykładzie tworzona jest seria domen aplikacji o nazwie AD0
za pomocą AD3
obiektu Worker
w każdej domenie aplikacji. Każdy Worker
obiekt ma odwołanie do Worker
obiektu w następnej domenie aplikacji, z wyjątkiem Worker
w ostatniej domenie aplikacji. Zdarzenie FirstChanceException jest obsługiwane we wszystkich domenach aplikacji z wyjątkiem AD1
.
Uwaga
Oprócz tego przykładu, który demonstruje powiadomienia o wyjątkach pierwszej szansy w wielu domenach aplikacji, można znaleźć proste przypadki użycia w temacie Instrukcje: odbieranie First-Chance powiadomienia o wyjątkach.
Po utworzeniu domen aplikacji domyślna domena aplikacji wywołuje metodę TestException
dla pierwszej domeny aplikacji. Każdy Worker
obiekt wywołuje metodę TestException
dla następnej domeny aplikacji, aż do ostatniego Worker
zgłoszenia wyjątku, który jest obsługiwany lub nieobsługiwany. W związku z tym bieżący wątek przechodzi przez wszystkie domeny aplikacji i TestException
jest dodawany do stosu w każdej domenie aplikacji.
Gdy ostatni Worker
obiekt obsługuje wyjątek, FirstChanceException zdarzenie jest zgłaszane tylko w ostatniej domenie aplikacji. Inne domeny aplikacji nigdy nie mają szans na obsługę wyjątku, więc zdarzenie nie jest zgłaszane.
Gdy ostatni Worker
obiekt nie obsługuje wyjątku, FirstChanceException zdarzenie jest zgłaszane w każdej domenie aplikacji, która ma procedurę obsługi zdarzeń. Po zakończeniu każdego programu obsługi zdarzeń stos będzie się odwijać, dopóki wyjątek nie zostanie przechwycony przez domyślną domenę aplikacji.
Uwaga
Aby zobaczyć, jak ekran stosu rośnie w miarę zbliżania się zdarzenia do domyślnej domeny aplikacji, zmień wartość e.Exception.Message
na e.Exception
w FirstChanceHandler
programach obsługi zdarzeń. Zwróć uwagę, że gdy TestException
jest wywoływana przez granice domeny aplikacji, pojawia się dwa razy: raz dla serwera proxy i raz dla wycinka.
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
Uwagi
To zdarzenie jest tylko powiadomieniem. Obsługa tego zdarzenia nie obsługuje wyjątku ani nie wpływa na obsługę kolejnych wyjątków w żaden sposób. Po wywołaniu zdarzenia i wywołaniu procedur obsługi zdarzeń środowisko uruchomieniowe języka wspólnego (CLR) rozpoczyna wyszukiwanie programu obsługi dla wyjątku. FirstChanceException udostępnia domenę aplikacji z pierwszą szansą na sprawdzenie wszelkich wyjątków zarządzanych.
Zdarzenie można obsłużyć dla domeny aplikacji. Jeśli wątek przechodzi przez wiele domen aplikacji podczas wykonywania wywołania, zdarzenie jest wywoływane w każdej domenie aplikacji, która zarejestrowała procedurę obsługi zdarzeń, zanim clR rozpocznie wyszukiwanie zgodnego programu obsługi wyjątków w tej domenie aplikacji. Po obsłużeniu zdarzenia wyszukiwanie jest wykonywane pod kątem zgodnego programu obsługi wyjątków w tej domenie aplikacji. Jeśli żaden z nich nie zostanie znaleziony, zdarzenie zostanie zgłoszone w następnej domenie aplikacji.
Należy obsługiwać wszystkie wyjątki występujące w procedurze obsługi zdarzeń dla zdarzenia FirstChanceException . FirstChanceException W przeciwnym razie jest wywoływana rekursywnie. Może to spowodować przepełnienie stosu i zakończenie działania aplikacji. Zalecamy zaimplementowanie procedur obsługi zdarzeń dla tego zdarzenia jako regionów wykonywania ograniczonych (CER), aby zachować wyjątki związane z infrastrukturą, takie jak brak pamięci lub przepełnienie stosu przed wpływem na maszynę wirtualną podczas przetwarzania powiadomienia o wyjątku.
To zdarzenie nie jest zgłaszane w przypadku wyjątków, które wskazują uszkodzenie stanu procesu, takie jak naruszenia dostępu, chyba że program obsługi zdarzeń ma krytyczne znaczenie dla zabezpieczeń i ma HandleProcessCorruptedStateExceptionsAttribute atrybut .
Środowisko uruchomieniowe języka wspólnego zawiesza przerywanie wątku podczas obsługi tego zdarzenia powiadomień.