2008-11-03 13 views
72

내 WinForms 앱은 데이터베이스에서 정보를 검색하기 위해 BackgroundWorker 개체를 사용합니다. BackgroundWorker는 장기 실행 데이터베이스 쿼리 중에 UI를 차단 해제 상태로 유지하고 스레드 모델을 단순화시켜주기 때문에 BackgroundWorker를 사용하고 있습니다.BackgroundWorker에서 처리되지 않은 예외가 발생했습니다.

이러한 백그라운드 스레드 중 일부에서 가끔 DatabaseExceptions이 발생하고 디버깅하는 동안 작업 스레드에서 이러한 예외 중 하나 이상을 목격했습니다. 나는이 예외가 시간 초과라고 생각하는 것을 상당히 확신한다.

제 질문은 이러한 백그라운드 작업자 스레드 중 하나에서 처리되지 않은 예외가 발생하면 어떻게되는지에 대한 것입니다.

다른 스레드에서 예외를 catch 할 수 있다고 생각하지 않지만 WorkerCompleted 메서드가 실행될 것으로 기대합니까? 거기에 어떤 속성이나 메서드를 BackgroundWorker 예외를 심문 할 수 있습니까?

답변

77

코드에서 처리하지 않는 예외가 발생하는 경우 BackgroundWorker은 예외를 catch하여 RunWorkerCompleted 이벤트 처리기로 전달합니다.이 처리기는 System.ComponentModel.RunWorkerCompletedEventArgs의 Error 속성으로 표시됩니다. Visual Studio 디버거에서 실행중인 경우 디버거는 처리되지 않은 예외가 발생한 DoWork 이벤트 처리기 지점에서 중단됩니다. 기본적으로

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.dowork.aspx

+5

그럴 겁니다. 물론 DoWork 메서드에서 예외를 catch하고 적절하게 대응할 수 있습니다 (UI를 업데이트하려는 경우 Control.Invoke를 사용하는 것을 기억하십시오). 그러나 RunWorkerCompleted는 실제로 더 간단합니다. –

+0

이 해결책을 찾고 있습니다. 새 예외()를 던질 때 내 RunWorkerCompleted가 실행되지 않지만 처리되지 않은 예외가 발생했습니다. DoWork를 잡는 것이 진정한 해결책은 아닙니다. 내 BackgroundWorker에 잘못된 것이 있어야합니다. – CallMeLaNN

+0

저는 방금 내 앱이 실행되지 않고 방금 종료 된 이유를 알아 내려고 지난 7 시간을 보냈습니다. 제대로 잡히지 않은 BackgroundWorker에서 오류가 발생했기 때문입니다. +1 당신과 나는 맥주도 마땅하다고 생각합니다 :-) – EvilDr

10

은이 잡힌과 BackgroundWorker에 의해 저장됩니다. MSDN에서 :

작업이 코드가 처리하지 않는 예외가 발생하는 경우, BackgroundWorker에 예외를 잡아가 System.ComponentModel.RunWorkerCompletedEventArgs의 오류 속성으로 노출되는 RunWorkerCompleted 이벤트 핸들러로 전달합니다 . Visual Studio 디버거에서 실행중인 경우 디버거는 처리되지 않은 예외가 발생한 DoWork 이벤트 처리기 지점에서 중단됩니다.

34

나는 완전히 BackgroundWorker을 1 년 넘게 사용하고 있으며 실제로 깊은 곳에서 알고 있습니다.

방금 ​​Throw New Exception("Test")DoWork을 입력하면 My RunWorkerCompletede.Error이 걸리지 않습니다. 그러나 처리되지 않은 예외가 발생했습니다. 따라서 DoWork을 잡는 것이 가장 좋은 습관이 아니기 때문에 e.Error은 아무런 의미가 없습니다.

새 을 새로 만들려고 시도하면 BackgroundWorker, e.ErrorRunWorkerCompleted으로 성공적으로 처리됩니다. 내 복잡한 BackgroundWorker에 잘못된 것이 있어야합니다.

Google 검색 및 디버깅 후 며칠간 오류가 발생했습니다. 내 RunWorkerCompleted이 발견 :

  • 확인 e.Error 첫째, 다음 e.Cancelled 그리고 마지막으로 e.Result
  • e.Resulte.Cancelled = True 경우를 얻을하지 마십시오.null (또는 Nothing)되지 않습니다 e.Resulte.Error 경우
  • 내가 그리워 곳입니다 ** **

을하지 마십시오. e.Errornull (또는 Nothing)이 아닌 경우 e.Result을 사용하려고하면 처리되지 않은 예외가 발생합니다.


업데이트 : e.Result에서 그것은, e.Error 첫째, 가지고있는 경우 오류를 확인하기 위해 다음 그들이 DoWork에서 같은 예외를 다시 throw합니다 속성 .NET 디자인을 얻을. 그렇기 때문에 처리되지 않은 예외는 RunWorkerCompleted에 있지만 실제로 예외는 DoWork에서 온 것입니다. 당신은 쉽게 할 수

Dim ThreadInfos as Dictionary(Of BackgroundWorker, YourObjectOrStruct) 

을 : 모든 DoWork, ProgressChanged 및 RunWorkerCompleted에 그 접근 객체, 다음과 같이 사용을 원하는 경우에

If e.Error IsNot Nothing Then 
    ' Handle the error here 
Else 
    If e.Cancelled Then 
    ' Tell user the process canceled here 
    Else 
    ' Tell user the process completed 
    ' and you can use e.Result only here. 
    End If 
End If 

: 여기

RunWorkerCompleted에서 할 수있는 최선의 방법입니다 원하는 위치로 ThreadInfos(sender).Field에 액세스하십시오.

+1

아니요. DoWork에 Throw New Exception ('Test')을 추가했습니다. 그런 다음 RunWorkerCompleted가 트리거되고 e.Result가 e.Error 전에 호출됩니다. 이것은 잘못된 것입니다. e.Error가 null (또는 Nothing)이 아니기 때문에 e.Result를 호출 할 수 없습니다. e.Error IsNot Nothing 또는 e.Cancelled = True 일 때 e.Result를 호출하면 RunWorkerCompleted에 처리되지 않은 예외가 발생합니다. e.Result를 호출하기 전에 e.Error와 e.Cancelled를 확인하십시오. – CallMeLaNN

+0

완료된 이벤트 핸들러에서 E.Result에 액세스하려고하면 DoWork가 오류가 발생했을 때 TargetInvocationException이 발생했습니다. 이제 오류가 null인지 또는 결과에 액세스하기 전에 취소 된 경우 코드가 수정되었는지 확인합니다. 귀하의 설명이 제 프로덕션 코드를 수정하는 데 도움이되었으므로이 사실을 알려 드리고자합니다. 정말 고마워! – jlafay

+0

@CallMeLaNN 우수 정보. 같은 실수를 저 지르지 않았습니까? –

4

이미 언급 한 바와 같이 : 작업이 코드가 처리하지 않는 예외 을 제기

경우, BackgroundWorker에이 곳은 예외 을 잡는다과 RunWorkerCompleted 이벤트 핸들러에 전달합니다 오류 속성이 인 System.ComponentModel.RunWorkerCompletedEventArgs로 표시됩니다.

원본 스레드와 상호 작용할 때마다 중요합니다. 예를 들어 예외의 결과를 폼의 어떤 종류의 레이블에 쓰고 싶다면 BackgroundWorker의 DoWork에서 예외를 catch하지 말고 대신 RunWorkerCompletedEventArgs에서 e.Error를 처리해야합니다.

반사경을 사용하여 BackgroundWorker 코드를 분석하면 모든 것이 매우 간단하게 처리됩니다. DoWork는 try-catch 블록에서 실행되고 예외는 RunWorkerCompleted로 전달됩니다. DoWork 이벤트에서 항상 모든 예외를 잡는 '선호 된'방법에 동의하지 않는 이유는 다음과 같습니다. 한마디로

는, 원래의 질문에 대답 :

을 - 당신은 항상 해고하기 위해 RunWorkerCompleted 셀 수 있습니다.

RunWorkerCompleted의 e.Error을 사용하여 다른 스레드의 예외를 확인하십시오.

3

이것은 디버거가 연결되지 않은 상태에서만 작동하며 Visual Studio에서 실행하면 디버거가 DoWork 메서드에서 처리되지 않은 예외를 catch하고 실행을 중단하지만 계속을 클릭하면 RunWorkerCompleted에 도달하게됩니다. e.Error 필드를 통해 예외를 읽을 수 있습니다.

관련 문제