Microsoft MVP성태의 닷넷 이야기
.NET Framework: 110. WPF - 전역 예외 처리 [링크 복사], [링크+제목 복사],
조회: 31933
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
(연관된 글이 1개 있습니다.)
(시리즈 글이 11개 있습니다.)
디버깅 기술: 6. .NET 예외 처리 정리
; https://www.sysnet.pe.kr/2/0/316

디버깅 기술: 15. First-Chance Exception
; https://www.sysnet.pe.kr/2/0/510

디버깅 기술: 16. Watson Bucket 정보를 이용한 CLR 응용 프로그램 예외 분석
; https://www.sysnet.pe.kr/2/0/595

.NET Framework: 110. WPF - 전역 예외 처리
; https://www.sysnet.pe.kr/2/0/614

디버깅 기술: 31. Windbg - Visual Studio 디버그 상태에서 종료해 버리는 응용 프로그램
; https://www.sysnet.pe.kr/2/0/957

디버깅 기술: 42. Watson Bucket 정보를 이용한 CLR 응용 프로그램 예외 분석 - (2)
; https://www.sysnet.pe.kr/2/0/1096

.NET Framework: 534. ASP.NET 응용 프로그램이 예외로 프로세스가 종료된다면?
; https://www.sysnet.pe.kr/2/0/10863

디버깅 기술: 110. 비동기 코드 실행 중 예외로 인한 ASP.NET 프로세스 비정상 종료 현상
; https://www.sysnet.pe.kr/2/0/11383

디버깅 기술: 119. windbg 분석 사례 - 종료자(Finalizer)에서 예외가 발생한 경우 비정상 종료(Crash) 발생
; https://www.sysnet.pe.kr/2/0/11732

닷넷: 2148. C# - async 유무에 따른 awaitable 메서드의 병렬 및 예외 처리
; https://www.sysnet.pe.kr/2/0/13422

닷넷: 2213. ASP.NET/Core 웹 응용 프로그램 - 2차 스레드의 예외로 인한 비정상 종료
; https://www.sysnet.pe.kr/2/0/13551





WPF 전역 예외 처리


WinForm과 WPF는 동일하게 "Application"이라는 이름의 타입을 사용하긴 하지만, 사실 이름만 같을 뿐 전체적인 구현 자체는 완전히 다른 구조입니다. 물론, 예외 처리도 많이 달라졌습니다.

우선, 이 토픽을 더 읽으시기 전에 예전에 소개해 드렸던 다음의 자료를 먼저 읽어보시길 바랍니다.

Debug Features : 4. .NET 예외 처리 정리 
; https://www.sysnet.pe.kr/2/0/316

중요한 것은 이 역시 ".NET Application"이기 때문에 기본적인 원칙은 벗어나지 않습니다. 즉, 모든 예외는 "AppDomain.CurrentDomain.UnhandledException"에서 처리되어질 수 있습니다.

하지만, WPF는 WinForm과 마찬가지로 Console 응용 프로그램 범주에 속하지 않습니다. 따라서 메시지 하나의 반응에 예외가 발생했다고 해서 전체 응용 프로그램 자체를 비정상 종료시킬 수는 없습니다. 그나마 WinForm에서는 Application.ThreadException을 통해서 UI 스레드에서 발생한 예외를 알아낼 수가 있고, Application.SetUnhandledExceptionMode를 통해서 예외 자체를 다시 rethrow 할 수 있도록 해주고 있는데요.

그렇다면, WPF에서는 어떻게 해야 처리되지 않은 예외로 인한 응용 프로그램의 비정상 종료를 막을 수 있을까요?

그 해답은 UI 스레드를 담당하고 있는 App.Dispatcher가 제공해 주고 있는데, 보통 아래와 같이 2개의 이벤트를 구독해서 처리해야 합니다.

public App()
{
    this.Dispatcher.UnhandledException += 
      new DispatcherUnhandledExceptionEventHandler(Dispatcher_UnhandledException);
      
    this.Dispatcher.UnhandledExceptionFilter += 
      new DispatcherUnhandledExceptionFilterEventHandler(Dispatcher_UnhandledExceptionFilter);
}

void Dispatcher_UnhandledExceptionFilter(object sender, 
    DispatcherUnhandledExceptionFilterEventArgs e)
{
    e.RequestCatch = true;
}

void Dispatcher_UnhandledException(object sender, 
    DispatcherUnhandledExceptionEventArgs e)
{
    MessageBox.Show(e.Exception.ToString());
    e.Handled = true;
}

사실, 개인적으로 왜 위와 같이 2단계의 예외 처리 이벤트를 두었는지는 이해할 수가 없습니다. 간단하게 살펴보면, UnhandledExceptionFilter 단계에서는 선택적으로 "e.RequestCatch" 변수에 true / false를 할당하는 것이 가능한데, 만약 여기에 true를 주면 비정상 종료되지 않고 false를 주면 응용 프로그램이 비정상종료를 하게 됩니다.

또한, e.RequestCatch 변수의 값에 상관없이 Dispatcher_UnhandledException 이벤트 처리기는 호출이 되어집니다. 중요한 것은, 이때에도 e.Handled 변수에 true 값을 할당해 주어야만 응용 프로그램이 비정상 종료 하는 것을 막을 수가 있습니다. 왜 이렇게 2가지 단계로 나뉘어야만 했을까요? 보시면 알겠지만, UnhandledExceptionFilter 이벤트 처리기 단계에서도 DispatcherUnhandledExceptionFilterEventArgs 매개변수(e.Exception)를 통해서 예외를 알아낼 수가 있습니다. 그러니 굳이 Dispatcher_UnhandledException 단계까지 갈 필요가 없음에도 불구하고.

마지막으로... 퀴즈 하나!
WPF 응용 프로그램에서 secondary thread에서 예외가 발생한 경우에는 어떻게 처리할 수 있을까요?



[이 토픽에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 5/21/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2008-11-16 06시56분
[지나가는 이] secondary thread는 AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

이걸로 처리 할 수 있는 건가요?
[guest]
2008-11-17 09시33분
넵. ^^
kevin25
2018-07-18 01시31분
[질문자] e.RequestCatch 와 e.Handled 모두 true 로 줬음에도 SEHException 이 발생하면서 프로그램이 종료되네요.
임의로 발생시킨 예외는 NullException 이에요.
[guest]
2018-07-18 04시30분
그러니까, 새 WPF 프로젝트 만들고 위의 코드가 반영된 상태에서 Window Loaded 이벤트에서 예외를 발생시키면 종료된다는 건가요?
정성태

... 121  122  123  124  125  126  127  128  129  130  [131]  132  133  134  135  ...
NoWriterDateCnt.TitleFile(s)
1780정성태10/15/201424230오류 유형: 249. The application-specific permission settings do not grant Local Activation permission for the COM Server application with CLSID
1779정성태10/15/201419758오류 유형: 248. Active Directory에서 OU가 지워지지 않는 경우
1778정성태10/10/201418212오류 유형: 247. The Netlogon service could not create server share C:\Windows\SYSVOL\sysvol\[도메인명]\SCRIPTS.
1777정성태10/10/201421323오류 유형: 246. The processing of Group Policy failed. Windows attempted to read the file \\[도메인]\sysvol\[도메인]\Policies\{...GUID...}\gpt.ini
1776정성태10/10/201418335오류 유형: 245. 이벤트 로그 - Name resolution for the name _ldap._tcp.dc._msdcs.[도메인명]. timed out after none of the configured DNS servers responded.
1775정성태10/9/201419460오류 유형: 244. Visual Studio 디버깅 (2) - Unable to break execution. This process is not currently executing the type of code that you selected to debug.
1774정성태10/9/201426652개발 환경 구성: 246. IIS 작업자 프로세스의 20분 자동 재생(Recycle)을 끄는 방법
1773정성태10/8/201429806.NET Framework: 471. 웹 브라우저로 다운로드가 되는 파일을 왜 C# 코드로 하면 안되는 걸까요? [1]
1772정성태10/3/201418614.NET Framework: 470. C# 3.0의 기본 인자(default parameter)가 .NET 1.1/2.0에서도 실행될까? [3]
1771정성태10/2/201428116개발 환경 구성: 245. 실행된 프로세스(EXE)의 명령행 인자를 확인하고 싶다면 - Sysmon [4]
1770정성태10/2/201421717개발 환경 구성: 244. 매크로 정의를 이용해 파일 하나로 C++과 C#에서 공유하는 방법 [1]파일 다운로드1
1769정성태10/1/201424138개발 환경 구성: 243. Scala 개발 환경 구성(JVM, 닷넷) [1]
1768정성태10/1/201419559개발 환경 구성: 242. 배치 파일에서 Thread.Sleep 효과를 주는 방법 [5]
1767정성태10/1/201424656VS.NET IDE: 94. Visual Studio 2012/2013에서의 매크로 구현 - Visual Commander [2]
1766정성태10/1/201422518개발 환경 구성: 241. 책 "프로그래밍 클로저: Lisp"을 읽고 나서. [1]
1765정성태9/30/201426064.NET Framework: 469. Unity3d에서 transform을 변수에 할당해 사용하는 특별한 이유가 있을까요?
1764정성태9/30/201422309오류 유형: 243. 파일 삭제가 안 되는 경우 - The action can't be comleted because the file is open in System
1763정성태9/30/201423879.NET Framework: 468. PDB 파일을 연동해 소스 코드 라인 정보를 알아내는 방법파일 다운로드1
1762정성태9/30/201424556.NET Framework: 467. 닷넷에서 EIP/RIP 레지스터 값을 구하는 방법 [1]파일 다운로드1
1761정성태9/29/201421620.NET Framework: 466. 윈도우 운영체제의 보안 그룹 이름 및 설명 문자열을 바꾸는 방법파일 다운로드1
1760정성태9/28/201419897.NET Framework: 465. ICorProfilerInfo::GetILToNativeMapping 메서드가 0x80131358을 반환하는 경우
1759정성태9/27/201430999개발 환경 구성: 240. Visual C++ / x64 환경에서 inline-assembly를 매크로 어셈블리로 대체하는 방법파일 다운로드1
1758정성태9/23/201437900개발 환경 구성: 239. 원격 데스크톱 접속(RDP)을 기존의 콘솔 모드처럼 사용하는 방법 [1]
1757정성태9/23/201418449오류 유형: 242. Lync로 모임 참여 시 소리만 들리지 않는 경우 - 두 번째 이야기
1756정성태9/23/201427472기타: 48. NVidia 제품의 과다한 디스크 사용 [2]
1755정성태9/22/201434261오류 유형: 241. Unity Web Player를 설치해도 여전히 설치하라는 화면이 나오는 경우 [4]
... 121  122  123  124  125  126  127  128  129  130  [131]  132  133  134  135  ...