全局捕获WPF应用程序中的异常?

时间:2009-04-27 11:16:34

标签: c# wpf exception exception-handling

我们正在使用WPF应用程序,其中部分可能会在运行时抛出异常。我想全局捕获任何未处理的异常并记录它们,但是否则继续执行程序就像没有发生任何事情一样(有点像VB的On Error Resume Next)。

这在C#中是否可行?如果是这样,我究竟需要将异常处理代码放在哪里?

目前,我无法看到任何可以包裹try / catch的单一点,哪些可以捕获可能发生的所有异常。即便如此,由于捕获,我会留下任何被执行的东西。或者我在这里想到可怕的错误方向?

ETA:因为下面有很多人指出:申请不是用于控制核电站。如果它崩溃了并不是什么大问题,但是大多数与UI相关的随机异常在它将被使用的上下文中是一种麻烦。有(也可能还有)其中的一些,因为它使用插件架构,可能会被其他人扩展(在这种情况下也是学生;所以没有经验丰富的开发人员能够完全编写错误 - 免费代码)。

至于被捕获的异常:我将它们记录到日志文件中,包括完整的堆栈跟踪。这就是这项工作的重点。只是为了对抗那些在字面上对VB的OERN进行类比的人。

我知道盲目地忽略某些类错误是危险的,可能会破坏我的应用程序实例。如前所述,这个程序对任何人来说都不是关键任务。在他们正确的思想中没有人会打赌人类文明的存在。它只是一个用于测试某些设计方法的小工具。软件工程。

为了立即使用该应用程序,异常可能会发生很多事情:

  • 无异常处理 - 错误对话框和应用程序退出。必须重复实验,尽管可能还有另一个主题。没有记录任何错误,这是不幸的。
  • 通用异常处理 - 陷入良性错误,没有造成伤害。这应该是我们在开发过程中看到的所有错误判断的常见情况。忽视这种错误不应该立即产生后果;核心数据结构经过充分测试,可以轻松应对。
  • 通用异常处理 - 严重错误被捕获,可能在以后崩溃。这可能很少发生。到目前为止我们从未见过它。无论如何都会记录错误,崩溃可能是不可避免的。所以这在概念上类似于第一种情况。除了我们有一个堆栈跟踪。在大多数情况下,用户甚至都不会注意到。

关于程序生成的实验数据:严重错误最坏的情况是不会导致数据被记录。稍微改变实验结果的微妙变化是不太可能的。即使在这种情况下,如果结果看起来很可疑,则会记录错误;如果它是一个完整的异常值,那么仍然可以扔掉那个数据点。

总结一下:是的,我认为自己仍然至少部分理智,我不认为一个全局异常处理例程让程序运行必然是完全邪恶的。如前所述,根据申请,这样的决定可能是有效的。在这种情况下,它被认为是一个有效的决定,而不是完全和彻底的废话。 对于任何其他可能看起来不同的应用程序。但请不要指责我或其他从事该项目的人因为忽略错误而可能炸毁世界。

附注:该应用程序只有一个用户。数百万人使用的不是像Windows或Office这样的东西,其中向用户提供异常泡沫的成本本来就已经非常不同了。

6 个答案:

答案 0 :(得分:170)

使用Application.DispatcherUnhandledException Event。有关摘要,请参阅this question(请参阅Drew Noakes' answer)。

请注意,在您尝试保存到数据库时,仍会存在阻止成功恢复应用程序的异常,例如堆栈溢出,内存耗尽或网络连接丢失。

答案 1 :(得分:30)

使用 NLog 的示例代码,它将捕获来自 UI调度程序线程中的所有线程以及的异常>异步功能

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

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

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

答案 2 :(得分:28)

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”中的方法,并从那里调用a   应用程序域“AD3”中的方法,它抛出异常。该   第一个应用程序域,UnhandledException事件可以在其中   提出的是“AD1”。如果该应用程序域不是默认值   在应用程序域中,事件也可以在默认情况下引发   应用领域。

答案 3 :(得分:17)

此外,其他人在此处提及,请注意将Application.DispatcherUnhandledException(及其similars)与

结合使用
<configuration>
  <runtime>  
    <legacyUnhandledExceptionPolicy enabled="1" />
  </runtime>
</configuration>
app.config中的

将阻止您的辅助线程异常关闭应用程序。

答案 4 :(得分:1)

以下是使用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);
        }        
    }


}

答案 5 :(得分:-3)

喜欢“VB的On Error Resume Next?”这听起来有点可怕。第一个建议是不要这样做。第二个建议是不要这样做,不要考虑它。您需要更好地隔离故障。至于如何解决这个问题,这取决于你的代码是如何构建的。如果你使用像MVC之类的模式,那么这应该不会太困难,并且肯定不需要全局异常吞噬。其次,寻找像log4net这样的好的日志库或使用跟踪。我们需要了解更多详细信息,例如您正在讨论的异常类型以及应用程序的哪些部分可能会导致异常被抛出。