在WPF应用程序中全局捕获异常?
在WPF应用程序中全局捕获异常?
我们有一个WPF应用程序,其中的某些部分可能会在运行时引发异常。我想全局捕获任何未处理的异常并记录它们,但是否则继续执行程序,就好像没有发生任何事情(有点像VB的On Error Resume Next
)。
在C#中是否有可能实现这一点? 如果是这样,我需要在哪里放置异常处理代码?
目前,我看不到任何单独的点可以将try
/catch
包装在周围,并且可以捕获可能发生的所有异常。 即使这样,由于catch而留下了执行的任何操作。 或者我在这里的想法非常错误?
注意:由于下面的许多人指出:该应用程序不用于控制核电站。如果它崩溃了,那就没有那么大的问题,但是它会抛出大多数与UI相关的随机异常,这在使用它的上下文中是令人讨厌的。有一些(可能仍然有)这样的异常,由于它使用插件架构并且可以由其他人扩展(在这种情况下也包括学生;因此没有经验丰富的开发人员能够编写完全无误的代码)。
对于被捕获的异常:我会将它们记录到日志文件中,包括完整的堆栈跟踪。这就是整个练习的全部意义。只是为了反驳那些过于字面解读我VB的OERN类比的人。
我知道盲目忽略某些错误类型是危险的,可能会损坏我的应用程序实例。如前所述,对于任何人来说,这个程序都不是使命关键的。没有一个人会在它上面下注保护人类文明的生存。它只是一种测试某些关于软件工程方面设计方法的小工具。
对于应用程序的即时使用,异常情况不会有太多的发生:
- 不处理异常 - 错误对话框和应用程序退出。试验必须重复,尽管可能使用另一个项目。没有记录任何错误,这是不幸的。
- 通用异常处理 - 无害错误被捕获,没有任何伤害。从我们在开发过程中看到的所有错误来看,这应该是常见情况。忽略这种类型的错误不应该有任何直接后果;核心数据结构足够测试,将轻松度过这一关。
- 通用异常处理 - 严重错误被捕获,可能会在稍后崩溃。这种情况很少发生。到目前为止,我们从未见过。无论如何都会记录错误,并且崩溃可能是不可避免的。因此,从概念上讲,它类似于第一种情况,只是我们有一个堆栈跟踪。在大多数情况下,用户甚至不会注意到这一点。
至于程序生成的实验数据:严重错误最坏的情况仅会导致未记录任何数据。微小变化轻微地改变实验结果的情况相当不可能。即使在这种情况下,如果结果看起来可疑,错误也已记录;如果这是一个离群点,仍然可以丢弃该数据点。
总之:是的,我认为自己仍然至少部分正常,而且我不认为一个全局异常处理过程即使保持程序运行也一定是完全邪恶的。正如之前两次所说,这样的决定可能是有效的,这取决于应用程序。在这种情况下,判断为一个有效的决定,而不是彻头彻尾的垃圾。 对于任何其他应用程序,这个决定可能会有所不同。但请不要因为我们忽略错误而指责我或其他工作在那个项目上的人有可能灭世。
附带说明:该应用程序只有一个用户。这不像Windows或Office这样被数百万人使用的软件,在这种情况下,异常被传递给用户的代价本身就会非常不同。
\n\n使用NLog的示例代码,可捕获从应用程序域中的所有线程、UI调度程序线程和异步函数抛出的异常:\n\n
App.xaml.cs :
\n
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); } }
使用Application.DispatcherUnhandledException
事件。请参见这个问题的总结(参见Drew Noakes的答案)。
请注意,仍然会有一些异常导致您的应用程序无法成功恢复,例如栈溢出后、内存不足或在尝试保存到数据库时失去了网络连接。