다음을 통해 공유


AppDomain.FirstChanceException 이벤트

정의

애플리케이션 도메인에서 런타임이 예외 처리기에 대한 호출 스택을 검색하기 전에 관리 코드에서 예외가 throw될 경우 발생합니다.

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) 

이벤트 유형

특성

예제

다음 예제에서는 일련의 명명 된 애플리케이션 도메인을 만듭니다 AD0 를 통해 AD3를 사용 하 여를 Worker 각 애플리케이션 도메인의 개체입니다. 각 Worker 개체에 대 한 참조에는 Worker 제외 하 고 다음 애플리케이션 도메인의 개체는 Worker 마지막 애플리케이션 도메인에서. 합니다 FirstChanceException 를 제외한 모든 애플리케이션 도메인에서 이벤트를 처리 AD1합니다.

참고

여러 애플리케이션 도메인에서 첫째 예외 알림을 보여 주는이 예제 외에도 간단한 사용 사례를 찾을 수 있습니다 방법: 첫째 예외 알림 받기합니다.

애플리케이션 도메인을 만든 경우 기본 애플리케이션 도메인 호출을 TestException 메서드 첫 번째 애플리케이션 도메인에 대 한 합니다. 각 Worker 호출 개체의 TestException 마지막까지 다음 애플리케이션 도메인에 대 한 메서드 Worker 처리 되거나 처리 되지 않은 예외를 throw 합니다. 따라서 현재 스레드는 모든 애플리케이션 도메인을 통해 전달 및 TestException 스택의 각 애플리케이션 도메인에 추가 됩니다.

때 마지막 Worker 개체에서 예외를 처리 합니다 FirstChanceException 마지막 애플리케이션 도메인에만 이벤트가 발생 합니다. 다른 애플리케이션 도메인 이벤트가 발생 하므로 예외를 처리 하는 받은 적입니다.

때 마지막 Worker 개체에서 예외를 처리 하지 않습니다는 FirstChanceException 이벤트는 이벤트 처리기가 각 애플리케이션 도메인에서 발생 합니다. 각 이벤트 처리기가 끝나면 스택 해제 예외는 기본 애플리케이션 도메인에서 발견 될 때까지 계속 합니다.

참고

변경 이벤트가 더 가까운 곳으로 스택 표시 증가 하는 방법 및 기본 애플리케이션 도메인에 가까울수록 서로 볼 e.Exception.Messagee.ExceptionFirstChanceHandler 이벤트 처리기입니다. 때 TestException 라고 애플리케이션 도메인 경계를 가로질러 두 번 나타납니다: 프록시에 한 번씩 및 스텁에 대 한 한 번입니다.

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

설명

이 이벤트는 알림일 뿐입니다. 이 이벤트를 처리해도 예외가 처리되지 않거나 후속 예외 처리에 어떤 식으로든 영향을 주지 않습니다. 이벤트가 발생하고 이벤트 처리기가 호출된 후 CLR(공용 언어 런타임)이 예외에 대한 처리기를 검색하기 시작합니다. FirstChanceException 관리 되는 모든 예외를 검사 하는 첫 번째 기회를 사용 하 여 애플리케이션 도메인을 제공 합니다.

애플리케이션 도메인 별로 이벤트를 처리할 수 있습니다. 스레드 호출을 실행 하는 동안 여러 애플리케이션 도메인을 통해 전달, CLR 해당 애플리케이션 도메인의 일치 하는 예외 처리기 검색을 시작 하기 전에 이벤트 처리기를 등록 된 각 애플리케이션 도메인에서 이벤트가 발생 합니다. 이벤트가 처리 된 후 해당 애플리케이션 도메인의 일치 하는 예외 처리기에 대 한 검색이 수행 됩니다. 미디어가 없는 경우 다음 애플리케이션 도메인에서 이벤트가 발생 합니다.

이벤트에 대한 이벤트 처리기에서 발생하는 모든 예외를 FirstChanceException 처리해야 합니다. 그렇지 않으면 가 FirstChanceException 재귀적으로 발생합니다. 이 스택 오버플로 및 애플리케이션이 종료 될 수 있습니다. 예외 알림이 처리되는 동안 메모리 부족 또는 스택 오버플로와 같은 인프라 관련 예외가 가상 머신에 영향을 주지 않도록 하려면 이 이벤트에 대한 이벤트 처리기를 제한된 실행 영역(CER)으로 구현하는 것이 좋습니다.

이 이벤트는 이벤트 처리기가 보안에 중요하고 특성이 없는 한 액세스 위반과 같은 프로세스 상태의 손상을 나타내는 예외에 HandleProcessCorruptedStateExceptionsAttribute 대해 발생하지 않습니다.

공용 언어 런타임은 이 알림 이벤트가 처리되는 동안 스레드 중단을 일시 중단합니다.

적용 대상

추가 정보