programing

WPF 어플리케이션에서 예외를 글로벌하게 포착하시겠습니까?

bestprogram 2023. 4. 12. 23:07

WPF 어플리케이션에서 예외를 글로벌하게 포착하시겠습니까?

WPF 어플리케이션의 일부에서 실행 시 예외가 발생할 수 있습니다.처리되지 않은 예외를 글로벌하게 포착하여 기록하고 싶지만, 그렇지 않으면 아무 일도 없었던 것처럼 프로그램 실행을 계속하고 싶다(VB와 같은 종류).On Error Resume Next를 참조해 주세요.

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

현재로선 포장을 할 수 있는 포인트가 하나도 보이지 않습니다.try/catch잡혔기 이다.그때도 나는 잡혔기 때문에 처형된 것은 무엇이든 남겼을 것이다.아니면 제가 끔찍하게 잘못된 방향으로 생각하고 있는 걸까요?

ETA: 아래 많은 분들이 지적하셨기 때문에:이 적용은 원자력발전소를 관리하기 위한 것이 아니다.크래시가 발생해도 큰 문제는 아니지만 UI와 관련된 랜덤 예외를 발생시켜 사용 상황에 방해가 됩니다.이 중 몇 개(아마도 현재도 마찬가지일 것입니다)는 플러그인 아키텍처를 사용하고 있으며 다른 사용자(이 경우 학생도 마찬가지입니다)에 의해 확장될 수 있기 때문에 완전히 오류가 없는 코드를 작성할 수 있는 경험이 있는 개발자는 없습니다.

적발된 예외에 대해서는:스택 트레이스 전체를 포함한 로그파일에 기록합니다.그것이 그 연습의 요점이었다.내가 VB의 OERN에 비유한 말 그대로의 사람들에 대항하기 위해서다.

특정 클래스의 오류를 맹목적으로 무시하는 것은 위험하고 응용 프로그램인스턴스를 손상시킬 수 있습니다.앞서 말했듯이, 이 프로그램은 누구에게나 미션 크리티컬하지 않습니다.제정신이라면 아무도 인류의 생존을 장담하지 않을 것이다.소프트웨어 엔지니어링과 같은 특정 설계 접근 방식을 테스트하기 위한 작은 도구일 뿐입니다.

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

  • 예외 처리 없음 – 오류 대화 상자 및 응용 프로그램 종료다른 주제로 실험을 반복해야 합니다.에러는 기록되어 있지 않습니다만, 유감입니다.
  • 일반적인 예외 처리– 무해한 오류가 포착되어 아무런 피해가 없습니다.이는 개발 과정에서 발생한 모든 오류로 판단되는 일반적인 경우입니다.이러한 종류의 오류를 무시해도 즉각적인 결과는 발생하지 않습니다.핵심 데이터 구조는 충분히 테스트되고 있기 때문에 쉽게 극복할 수 있습니다.
  • 일반적인 예외 처리– 중대한 오류가 포착되어 나중에 크래시 될 수 있습니다.이런 일은 거의 일어나지 않을 수 있습니다.우리는 지금까지 그것을 본 적이 없다.에러가 로그에 기록되기 때문에, 크래시가 불가피할 가능성이 있습니다.이것은 개념적으로 첫 번째 케이스와 비슷하지만 스택트레이스가 있다는 점이 다릅니다.그리고 대부분의 경우 사용자는 알아차리지도 못할 것입니다.

프로그램에 의해 생성된 실험 데이터에 대해서는:심각한 오류는 최악의 경우 데이터가 기록되지 않습니다.실험 결과를 아주 조금이나마 바꾸는 미묘한 변화는 있을 것 같지 않다.그리고 이 경우에도 결과가 불확실한 경우 오류가 기록되었습니다. 데이터 포인트가 완전히 특이치일 경우 이 데이터 포인트는 폐기할 수 있습니다.

요약:네, 저는 제 자신이 적어도 부분적으로 제정신이라고 생각합니다.또한 프로그램을 실행시키는 글로벌 예외 처리 루틴이 반드시 악하다고는 생각하지 않습니다.앞서 두 번 말한 바와 같이, 어플리케이션에 따라서는 이러한 결정이 유효할 수 있습니다.이 경우 그것은 타당한 결정으로 판단되었고 완전하고 완전한 헛소리는 아니었다.다른 어플리케이션에서는 이 결정이 달라 보일 수 있습니다.하지만 그 프로젝트에 참여한 저나 다른 사람들이 우리가 오류를 무시하고 있다고 해서 세상을 폭파시킬 수 있다고 비난하지는 말아주세요.

사이드 노트:그 어플리케이션에는 정확히 1명의 사용자가 있습니다.수백만 명이 사용하는 Windows나 Office와 같은 것이 아닙니다.사용자에 대한 예외 버블의 비용은 애초에 크게 다를 것입니다.

개요를 보려면 이 질문을 참조하십시오(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.Unhandled Exception 이벤트

이 이벤트는 수집되지 않은 예외에 대한 알림을 제공합니다.이를 통해 시스템 기본 핸들러가 예외를 사용자에게 보고하고 응용 프로그램을 종료하기 전에 응용 프로그램이 예외에 대한 정보를 기록할 수 있습니다.

   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);
   }

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

예를 들어 스레드가 응용 프로그램 도메인 "AD1"에서 시작하여 응용 프로그램 도메인 "AD2"에서 메서드를 호출하고 거기에서 응용 프로그램 도메인 "AD3"에서 메서드를 호출하여 예외를 발생시킨다고 가정합니다.Unhandled Exception 이벤트를 발생시킬 수 있는 첫 번째 응용 프로그램 도메인은 "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);
        }        
    }


}

Wpf 어플리케이션프로젝트에서 다음 단계를 수행합니다.

App.xaml.cs 파일:

'시스템'을 클릭합니다.창문들.스레드화'

create App_DispatcherUnhandledException 메서드도 같은 예입니다.

예:

    using System.Windows;
    using System.Windows.Threading;
    
    namespace Test
    {
        public partial class App : Application
        {
            
    
        void App_DispatcherUnhandledException(object sender,                                 
                                  
                    DispatcherUnhandledExceptionEventArgs e)
            {
                // Process unhandled exception
    
                // Prevent default unhandled exception processing
    
                e.Handled = true;
            }
    
        }
    }

App.xaml:

DispatcherUnhandledException= 추가"App_DispatcherUnhandledException"

예:

<Application x:Class="eValGr.UI.Light.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:eValGr.UI.Light"
             DispatcherUnhandledException="Application_DispatcherUnhandledException">
    <Application.Resources>
    </Application.Resources>
</Application>

예를 들어 "VB's On Error Resume Next?"와 같이요.좀 무섭게 들리네요.첫 번째 추천은 하지 않는 것입니다.두 번째 추천은 하지 말고 생각하지 마세요.너는 너의 결점을 더 잘 분리할 필요가 있다.이 문제에 대한 접근 방법은 코드 구성에 따라 달라집니다.MVC와 같은 패턴을 사용하고 있다면, 이것은 그다지 어렵지 않고, 글로벌한 예외 삼킴이도 필요 없습니다.다음으로 log4net과 같은 양호한 로깅 라이브러리를 찾거나 트레이스를 사용합니다.어떤 예외에 대해 이야기하고 있는지, 어떤 부분에서 예외가 발생할 수 있는지 등에 대해 자세히 알아야 합니다.

언급URL : https://stackoverflow.com/questions/793100/globally-catch-exceptions-in-a-wpf-application