[C#] WPF 응용 프로그램에서 전역 적으로 예외를 포착합니까?

우리는 런타임에 일부가 예외를 throw 할 수있는 WPF 응용 프로그램을 가지고 있습니다. 처리되지 않은 예외를 전역 적으로 잡아서 기록하고 싶지만 아무 일도없는 것처럼 프로그램 실행을 계속하고 싶습니다 (VB와 같은 On Error Resume Next).

C #에서 가능합니까? 그렇다면 예외 처리 코드를 정확히 어디에 두어야합니까?

현재 나는 try/ catcharound를 감싸고 발생할 수있는 모든 예외를 포착 할 수있는 단일 지점을 볼 수 없습니다 . 그리고 그때에도 나는 잡기로 인해 처형 된 것을 남겼습니다. 아니면 내가 끔찍하게 잘못된 방향으로 생각하고 있습니까?

ETA : 아래의 많은 사람들이 지적한 바에 따르면 :이 응용 프로그램은 원자력 발전소를 제어하기위한 것이 아닙니다. 충돌이 발생하면 그다지 중요하지 않지만 대부분 UI와 관련된 임의의 예외는 사용되는 컨텍스트에서 성가신 것입니다. 그중 몇 가지가 있었으며 플러그인 아키텍처를 사용하고 다른 사람들에 의해 확장 될 수 있기 때문에 (이 경우 학생도 가능하므로 완전히 오류가없는 코드를 작성할 수있는 숙련 된 개발자는 없습니다 ).

잡힌 예외에 관해서는 완전한 스택 추적을 포함하여 로그 파일에 기록합니다. 그것이 그 운동의 요점이었습니다. VB의 OERN에 ​​비유 한 사람들을 문자 그대로 대하는 것입니다.

특정 클래스의 오류를 맹목적으로 무시하는 것은 위험하며 애플리케이션 인스턴스가 손상 될 수 있음을 알고 있습니다. 앞에서 말했듯이,이 프로그램은 누구에게도 중요하지 않습니다. 그들의 올바른 마음에 아무도 인류 문명의 생존에 내기를 걸었을 것입니다. 그것은 특정 디자인 접근법을 테스트하기위한 작은 도구 일뿐입니다. 소프트웨어 공학.

응용 프로그램을 즉시 사용하기 위해 예외에서 발생할 수있는 일이 많지 않습니다.

  • 예외 처리 없음 – 오류 대화 상자 및 응용 프로그램 종료. 다른 주제와 마찬가지로 실험을 반복해야합니다. 불행히도 오류가 기록되지 않았습니다.
  • 일반적인 예외 처리 – 양성 오류 포착, 피해 없음. 이것은 개발 과정에서 우리가보고 있던 모든 오류로 판단되는 일반적인 사례입니다. 이런 종류의 오류를 무시해도 즉각적인 결과는 없습니다. 핵심 데이터 구조는이를 쉽게 극복 할 수있을 정도로 충분히 테스트되었습니다.
  • 일반적인 예외 처리 – 심각한 오류가 발생하여 나중에 중단 될 수 있습니다. 거의 발생하지 않을 수 있습니다. 우리는 지금까지 본 적이 없습니다. 어쨌든 오류가 기록되고 충돌이 불가피 할 수 있습니다. 이것은 개념적으로 첫 번째 경우와 유사합니다. 스택 추적을 제외하고. 그리고 대부분의 경우 사용자는 눈치 채지 못할 것입니다.

프로그램에 의해 생성 된 실험 데이터의 경우 : 심각한 오류는 최악의 경우 데이터를 기록하지 않습니다. 실험 결과를 약간 변화시키는 미묘한 변화는 거의 없을 것입니다. 이 경우에도 결과가 모호한 것처럼 보이면 오류가 기록되었습니다. 전체 이상치 인 경우 해당 데이터 포인트를 버릴 수 있습니다.

요약하자면, 그렇습니다. 나는 여전히 부분적으로 제정신이라고 생각하며 프로그램을 실행하는 것이 완전히 악의적 인 전역 예외 처리 루틴을 고려하지 않습니다. 전에 두 번 언급했듯이, 그러한 결정은 응용 프로그램에 따라 유효 할 수 있습니다. 이 경우에 그것은 유효한 결정으로 판결되었고 총체적이고 완전한 헛소리가 아닙니다. 다른 응용 프로그램의 경우 결정이 다르게 보일 수 있습니다. 그러나 저 또는 그 프로젝트에서 일한 다른 사람들이 우리가 실수를 무시하고 있기 때문에 세상을 날려 버릴 수 있다고 비난하지 마십시오.

참고 : 해당 응용 프로그램에는 정확히 한 명의 사용자가 있습니다. Windows 또는 Office와 같이 수백만 명의 사람들이 사용하는 예외는 아닙니다. 사용자에게 예외가 발생하는 비용은 처음부터 매우 다릅니다.



답변

를 사용하십시오 Application.DispatcherUnhandledException Event. 요약을 보려면 이 질문 을 참조하십시오 ( Drew Noakes의 답변 참조 ).

데이터베이스에 저장하려고 할 때 스택 오버플로, 메모리 부족 또는 네트워크 연결 끊김 후와 같이 응용 프로그램을 성공적으로 다시 시작하지 못하게하는 예외가 여전히 있습니다.


답변

AppDomain의 모든 스레드 , UI 디스패처 스레드비동기 함수 에서 발생한 예외를 포착 하는 NLog 사용 예제 코드 :

App.xaml.cs :

public partial class App : Application
{
    private static Logger _logger = LogManager.GetCurrentClassLogger();

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        SetupExceptionHandling();
    }

    private void SetupExceptionHandling()
    {
        AppDomain.CurrentDomain.UnhandledException += (s, e) =>
            LogUnhandledException((Exception)e.ExceptionObject, "AppDomain.CurrentDomain.UnhandledException");

        DispatcherUnhandledException += (s, e) =>
        {
            LogUnhandledException(e.Exception, "Application.Current.DispatcherUnhandledException");
            e.Handled = true;
        };

        TaskScheduler.UnobservedTaskException += (s, e) =>
        {
            LogUnhandledException(e.Exception, "TaskScheduler.UnobservedTaskException");
            e.SetObserved();
        };
    }

    private void LogUnhandledException(Exception exception, string source)
    {
        string message = $"Unhandled exception ({source})";
        try
        {
            System.Reflection.AssemblyName assemblyName = System.Reflection.Assembly.GetExecutingAssembly().GetName();
            message = string.Format("Unhandled exception in {0} v{1}", assemblyName.Name, assemblyName.Version);
        }
        catch (Exception ex)
        {
            _logger.Error(ex, "Exception in LogUnhandledException");
        }
        finally
        {
            _logger.Error(exception, message);
        }
    }


답변

AppDomain.UnhandledException 이벤트

이 이벤트는 포착되지 않은 예외에 대한 알림을 제공합니다. 시스템 기본 핸들러가 예외를 사용자에게보고하고 애플리케이션을 종료하기 전에 애플리케이션이 예외에 대한 정보를 로그 할 수 있습니다.

   public App()
   {
      AppDomain currentDomain = AppDomain.CurrentDomain;
      currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
   }

   static void MyHandler(object sender, UnhandledExceptionEventArgs args)
   {
      Exception e = (Exception) args.ExceptionObject;
      Console.WriteLine("MyHandler caught : " + e.Message);
      Console.WriteLine("Runtime terminating: {0}", args.IsTerminating);
   }

UnhandledException 이벤트가 기본 응용 프로그램 도메인에서 처리되는 경우 스레드가 시작된 응용 프로그램 도메인에 관계없이 스레드에서 처리되지 않은 예외가 발생하면 이벤트가 발생합니다. UnhandledException에 대한 이벤트 처리기가있는 응용 프로그램 도메인에서 스레드가 시작된 경우, 해당 응용 프로그램 도메인에서 이벤트가 발생합니다. 해당 응용 프로그램 도메인이 기본 응용 프로그램 도메인이 아니고 기본 응용 프로그램 도메인에도 이벤트 핸들러가있는 경우 두 응용 프로그램 도메인 모두에서 이벤트가 발생합니다.

예를 들어 스레드가 응용 프로그램 도메인 “AD1″에서 시작하고 응용 프로그램 도메인 “AD2″의 메서드를 호출 한 다음 응용 프로그램 도메인 “AD3″의 메서드를 호출한다고 가정하면 예외가 발생합니다. UnhandledException 이벤트가 발생할 수있는 첫 번째 응용 프로그램 도메인은 “AD1″입니다. 해당 응용 프로그램 도메인이 기본 응용 프로그램 도메인이 아닌 경우 기본 응용 프로그램 도메인에서 이벤트가 발생할 수도 있습니다.


답변

또한 다른 사람들이 여기에 언급 한 내용 Application.DispatcherUnhandledException과 (및 유사 항목 )을

<configuration>
  <runtime>
    <legacyUnhandledExceptionPolicy enabled="1" />
  </runtime>
</configuration>

에서 app.config보조 스레드 예외가 응용 프로그램을 종료하지 못하게합니다.


답변

다음은 다음을 사용한 완전한 예입니다. NLog

using NLog;
using System;
using System.Windows;

namespace MyApp
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        private static Logger logger = LogManager.GetCurrentClassLogger();

        public App()
        {
            var currentDomain = AppDomain.CurrentDomain;
            currentDomain.UnhandledException += CurrentDomain_UnhandledException;
        }

        private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            var ex = (Exception)e.ExceptionObject;
            logger.Error("UnhandledException caught : " + ex.Message);
            logger.Error("UnhandledException StackTrace : " + ex.StackTrace);
            logger.Fatal("Runtime terminating: {0}", e.IsTerminating);
        }
    }


}


답변

“VB의 On Error Resume Next?”와 같이 좀 무섭다. 첫 번째 권장 사항은 그렇게하지 않는 것입니다. 두 번째 권장 사항은하지 말고 생각하지 마십시오. 당신은 당신의 잘못을 더 잘 분리해야합니다. 이 문제에 접근하는 방법은 코드가 어떻게 구성되어 있는지에 달려 있습니다. MVC와 같은 패턴을 사용하는 경우 이것은 어렵지 않으며 전역 예외 삼키기가 필요하지 않습니다. 둘째, log4net과 같은 좋은 로깅 라이브러리를 찾거나 추적을 사용하십시오. 어떤 종류의 예외에 대해 이야기하고 있고 어떤 부분에서 예외가 발생할 수 있는지에 대한 자세한 내용을 알아야합니다.


답변