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

Joe*_*oey 228 c# wpf exception-handling exception

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

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

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

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

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

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

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

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

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

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

附注:该应用程序只有一个用户.数百万人使用的不是像Windows或Office这样的东西,在这种情况下,向用户提供异常泡沫的成本本来就是非常不同的.

Dav*_*itt 180

使用Application.DispatcherUnhandledException Event.请参阅此问题以获得摘要(请参阅Drew Noakes的回答).

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

  • 如果您的异常发生在后台线程上(例如,使用ThreadPool.QueueUserWorkItem),这将不起作用. (13认同)
  • 看来我们需要设置e.Handled = true,其中e是DispatcherUnhandledExceptionEventArgs,以跳过退出程序的默认处理程序.http://msdn.microsoft.com/en-us/library/system.windows.application.dispatcherunhandledexception.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-3 (3认同)

Hüs*_*ğlı 44

使用示例代码NLOG,将捕获从抛出的异常的AppDomain中的所有线程,从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");

        Dispatcher.UnhandledException += (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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 这是最完整的答案!包括Taks调度程序例外.最适合我,干净简单的代码. (7认同)
  • 最近我在一个客户那里发现了一个 App.config 损坏,她的应用程序甚至没有启动,因为 NLog 试图从 App.config 读取并抛出异常。由于该异常_在静态记录器初始值设定项中_,它没有被 `UnhandledException` 处理程序捕获。我不得不查看 Windows 事件日志查看器才能找到发生了什么...... (3认同)

Cha*_*thJ 29

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);
   }
Run Code Online (Sandbox Code Playgroud)

如果在默认应用程序域中处理UnhandledException事件,则会在任何线程中针对任何未处理的异常引发它,无论线程启动的是什么应用程序域.如果线程在具有UnhandledException的事件处理程序的应用程序域中启动,该事件在该应用程序域中引发.如果该应用程序域不是默认应用程序域,并且默认应用程序域中也存在事件处理程序,则会在两个应用程序域中引发该事件.

例如,假设一个线程在应用程序域"AD1"中启动,在应用程序域"AD2"中调用一个方法,并从那里调用应用程序域"AD3"中的一个方法,它会抛出异常.可以引发UnhandledException事件的第一个应用程序域是"AD1".如果该应用程序域不是默认应用程序域,则还可以在默认应用程序域中引发该事件.


Her*_*ess 17

除了其他人在这里提到的,请注意将 Application.DispatcherUnhandledException(和它的类似物)结合起来

<configuration>
  <runtime>  
    <legacyUnhandledExceptionPolicy enabled="1" />
  </runtime>
</configuration>
Run Code Online (Sandbox Code Playgroud)

app.config将防止您的辅助线程异常关闭应用程序.