Application.ThreadException 이벤트 핸들러에서 전체 예외 체인을 얻는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/61354

  •  09-06-2019
  •  | 
  •  

문제

.NET 2.0 앱의 예외 처리 문제를 해결하는 중이었는데 다음과 같은 이상한 문제를 발견했습니다. 애플리케이션.스레드예외.

내가 원하는 것은 GUI 요소 뒤의 이벤트에서 모든 예외를 포착할 수 있는 것입니다(예:버튼_클릭 등).그런 다음 '치명성'에 대한 예외를 필터링하고 싶습니다.일부 예외 유형의 경우 애플리케이션은 계속 실행되어야 하고 다른 유형의 경우에는 종료되어야 합니다.

다른 .NET 2.0 앱에서는 기본적으로 디버그 모드에서만 예외가 실제로 Application.Run 또는 Application.DoEvents 호출을 떠난다는 것을 알게 되었습니다.릴리스 모드에서는 이런 일이 발생하지 않으며, Application.ThreadException 이벤트를 사용하여 예외를 '잡아야' 합니다.

그러나 이제 나는 깨달았습니다. Application.ThreadException 이벤트의 ThreadExceptionEventArgs에 전달된 예외 개체는 항상 예외 체인에서 가장 안쪽 예외입니다..로깅/디버깅/디자인 목적을 위해 나는 전체 예외 체인을 정말로 원합니다.예를 들어 SocketException을 처리하려고 할 때 어떤 외부 시스템이 실패했는지 확인하는 것은 쉽지 않습니다.예를 들어 포장되었을 때NpgsqlException이 발생한 경우 적어도 데이터베이스 문제라는 것을 알 수 있습니다.

그렇다면 이 이벤트에서 전체 예외 체인에 어떻게 접근할 수 있을까요? 가능합니까, 아니면 예외 처리를 다른 방식으로 설계해야 합니까?

나는 일종의- 해결 방법 사용하여 Application.SetUnhandledExceptionMode, 그러나 이것은 내 자신의 메시지 루프를 굴려야 하기 때문에 이상적이 아닙니다.

편집하다:더 이상의 실수를 방지하기 위해, GetBaseException() 메서드가 내가 원하는 것을 수행하지 않습니다.:가장 안쪽 예외만 반환하는 반면, 내가 이미 가지고 있는 유일한 것은 가장 안쪽 예외뿐입니다.가장 바깥쪽 예외를 확인하고 싶습니다!

도움이 되었습니까?

해결책

다른 팁

나는 이 동작을 재현하려고 시도했습니다(항상 가장 안쪽 예외가 발생함).
하지만 모든 InnerExceptions가 그대로 유지되면서 예상한 예외가 발생합니다.

테스트에 사용한 코드는 다음과 같습니다.

   Private Shared Sub Test1()
      Try
         Test2()
      Catch ex As Exception
         Application.OnThreadException(New ApplicationException("test1", ex))
      End Try
   End Sub

   Private Shared Sub Test2()
      Try
         Test3()
      Catch ex As Exception
         Throw New ApplicationException("test2", ex)
      End Try
   End Sub

   Private Shared Sub Test3()
      Throw New ApplicationException("blabla")
   End Sub

Private Shared Sub HandleAppException(ByVal sender As Object, ByVal e As ThreadExceptionEventArgs)
...
End Sub

하위 HandleAppException은 Application.ThreadException을 처리합니다.Test1() 메서드가 먼저 호출됩니다.
이것은 HandleAppException에서 얻은 결과(예: ThreadExceptionEventArgs)입니다.

ThreadException http://mediasensation.be/dump/?download=ThreadException.jpg

예외를 포착하고 (다시) 던지면 InnerException이 표시되지 않지만 예외에 추가됩니다.스택트레이스, 이와 같이:

Test.vb:line 166의 SO.Test3()에서
Test.vb:line 159의 SO.Test2()에서
Test.vb:line 151의 SO.Test1()에서

일반적으로 다른 스레드에서 예외가 발생한 경우 Application.ThreadException 예외 처리기의 기본 예외를 제외한 전체 예외 체인만 손실됩니다.

로부터 MSDN 라이브러리:

이 이벤트는 Windows Forms 응용 프로그램에서 발생하지 않는 예외를 처리 할 수 ​​있습니다. 윈도우 폼 스레드.이벤트 핸들러를 ThreadException 이벤트에 첨부하여 이러한 예외를 처리하여 응용 프로그램을 알려지지 않은 상태로 남길 것입니다.가능한 경우 예외는 구조화 된 예외 처리 블록으로 처리해야합니다.

해결책:스레딩을 수행하는 경우 모든 스레드/비동기 호출이 try/catch 블록에 있는지 확인하세요.또는 말씀하신 대로 Application.SetUnhandledExceptionMode를 사용하여 재생할 수 있습니다.

방금 흥미로운 것을 발견했습니다.GUI 이벤트에 따라 결과가 달라집니다.Form.Shown 이벤트 핸들러에서 예외가 발생하면 Application.ThreadException이 가장 안쪽 예외를 포착하게 되지만, Form.Load 이벤트에서 정확히 동일한 코드를 실행하면 다음과 같은 결과가 발생합니다. 가장 바깥쪽 Application.ThreadException에서 예외가 발생합니다.

Exception.GetBaseException 메서드를 사용해 보셨나요?이는 Application.TreadException을 생성한 예외를 반환합니다.그런 다음 동일한 프로세스를 사용하여 체인 위로 이동하여 모든 예외를 얻을 수 있습니다.

예외.getbaseException 메서드

이 체인의 일부 정보를 기반으로 UnhandledExceptionMode.CatchException이 아닌 UnhandledExceptionMode.ThrowException을 사용했습니다.그런 다음 양식의 Run() 외부에서 예외를 포착하면 전체 예외 체인이 제공됩니다.

MSDN 문서에 따르면:

파생 클래스에서 재정의되면 하나 이상의 후속 예외의 근본 원인인 예외를 반환합니다.

    Public Overridable Function GetBaseException() As Exception
        Dim innerException As Exception = Me.InnerException
        Dim exception2 As Exception = Me
        Do While (Not innerException Is Nothing)
            exception2 = innerException
            innerException = innerException.InnerException
        Loop
        Return exception2
    End Function

이에 대한 변형을 사용하여 예외 체인을 구문 분석할 수 있습니다.

Public Sub LogExceptionChain(ByVal CurrentException As Exception)

    Dim innerException As Exception = CurrentException.InnerException
    Dim exception2 As Exception = CurrentException

    Debug.Print(exception2.Message) 'Log the Exception

    Do While (Not innerException Is Nothing)

        exception2 = innerException
        Debug.Print(exception2.Message) 'Log the Exception

        'Move to the next exception
        innerException = innerException.InnerException
    Loop

End Sub

이것은 당신이 찾고 있는 것과 정확히 일치할 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top