C# 是否应该同时使用 AppDomain.UnhandledException 和 Application.DispatcherUnhandledException?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10061287/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Should use both AppDomain.UnhandledException and Application.DispatcherUnhandledException?
提问by Kyle
After reading some excellent posts about the difference between AppDomain.UnhandledException and Application.DispatcherUnhandledException, it appears that I should be handling both. This is because it is significantly more likely the user can recover from an exception thrown by the main UI thread (i.e., Application.DispatcherUnhandledException). Correct?
在阅读了一些关于 AppDomain.UnhandledException 和 Application.DispatcherUnhandledException 之间区别的优秀帖子后,我似乎应该同时处理这两者。这是因为用户从主 UI 线程抛出的异常(即 Application.DispatcherUnhandledException)中恢复的可能性要大得多。正确的?
Also, should I also give the user a chance to continue the program for both, or just the Application.DispatcherUnhandledException?
另外,我是否还应该让用户有机会为两者继续该程序,还是只让 Application.DispatcherUnhandledException 继续该程序?
Example code below handles both AppDomain.UnhandledException and Application.DispatcherUnhandledException, and both give the user the option to try to continue despite the exception.
下面的示例代码处理 AppDomain.UnhandledException 和 Application.DispatcherUnhandledException,并且都为用户提供了尽管出现异常仍尝试继续的选项。
[thanks and some of the code below is lifted from other answers]
[谢谢,下面的一些代码是从其他答案中提取的]
App.xaml
应用程序.xaml
<Application x:Class="MyProgram.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Startup="App_StartupUriEventHandler"
Exit="App_ExitEventHandler"
DispatcherUnhandledException="AppUI_DispatcherUnhandledException">
<Application.Resources>
</Application.Resources>
</Application>
App.xaml.cs [redacted]
App.xaml.cs [已编辑]
/// <summary>
/// Add dispatcher for Appdomain.UnhandledException
/// </summary>
public App()
: base()
{
this.Dispatcher.UnhandledException += OnDispatcherUnhandledException;
}
/// <summary>
/// Catch unhandled exceptions thrown on the main UI thread and allow
/// option for user to continue program.
/// The OnDispatcherUnhandledException method below for AppDomain.UnhandledException will handle all other exceptions thrown by any thread.
/// </summary>
void AppUI_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
if (e.Exception == null)
{
Application.Current.Shutdown();
return;
}
string errorMessage = string.Format("An application error occurred. If this error occurs again there seems to be a serious bug in the application, and you better close it.\n\nError:{0}\n\nDo you want to continue?\n(if you click Yes you will continue with your work, if you click No the application will close)", e.Exception.Message);
//insert code to log exception here
if (MessageBox.Show(errorMessage, "Application User Interface Error", MessageBoxButton.YesNoCancel, MessageBoxImage.Error) == MessageBoxResult.No)
{
if (MessageBox.Show("WARNING: The application will close. Any changes will not be saved!\nDo you really want to close it?", "Close the application!", MessageBoxButton.YesNoCancel, MessageBoxImage.Warning) == MessageBoxResult.Yes)
{
Application.Current.Shutdown();
}
}
e.Handled = true;
}
/// <summary>
/// Catch unhandled exceptions not thrown by the main UI thread.
/// The above AppUI_DispatcherUnhandledException method for DispatcherUnhandledException will only handle exceptions thrown by the main UI thread.
/// Unhandled exceptions caught by this method typically terminate the runtime.
/// </summary>
void OnDispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
string errorMessage = string.Format("An application error occurred. If this error occurs again there seems to be a serious bug in the application, and you better close it.\n\nError:{0}\n\nDo you want to continue?\n(if you click Yes you will continue with your work, if you click No the application will close)", e.Exception.Message);
//insert code to log exception here
if (MessageBox.Show(errorMessage, "Application UnhandledException Error", MessageBoxButton.YesNoCancel, MessageBoxImage.Error) == MessageBoxResult.No)
{
if (MessageBox.Show("WARNING: The application will close. Any changes will not be saved!\nDo you really want to close it?", "Close the application!", MessageBoxButton.YesNoCancel, MessageBoxImage.Warning) == MessageBoxResult.Yes)
{
Application.Current.Shutdown();
}
}
e.Handled = true;
}
采纳答案by Mike Fuchs
AppDomain.CurrentDomain.UnhandledExceptionin theory catches all exceptions on all threads of the appdomain. I found this to be very unreliable, though.Application.Current.DispatcherUnhandledExceptioncatches all exceptions on the UI thread. This seems to work reliably, and will replace theAppDomain.CurrentDomain.UnhandledExceptionhandler on the UI thread (takes priority). Usee.Handled = trueto keep the application running.For catching exceptions on other threads (in the best case, they are handled on their own thread), I found System.Threading.Tasks.Task (only .NET 4.0 and above) to be low-maintenance. Handle exceptions in tasks with the method
.ContinueWith(...,TaskContinuationOptions.OnlyOnFaulted). See my answer herefor details.
AppDomain.CurrentDomain.UnhandledException理论上会捕获 appdomain 的所有线程上的所有异常。不过,我发现这是非常不可靠的。Application.Current.DispatcherUnhandledException捕获 UI 线程上的所有异常。这似乎工作可靠,并将替换AppDomain.CurrentDomain.UnhandledExceptionUI 线程上的处理程序(优先)。使用e.Handled = true以保持应用程序的运行。为了捕获其他线程上的异常(在最好的情况下,它们在自己的线程上处理),我发现 System.Threading.Tasks.Task(仅 .NET 4.0 及更高版本)维护成本低。使用方法处理任务中的异常
.ContinueWith(...,TaskContinuationOptions.OnlyOnFaulted)。有关详细信息,请参阅我的答案here。
回答by Ricibob
An AppDomain.UnhandledExceptionhandler is wired as:
一个AppDomain.UnhandledException处理器是有线作为:
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
But I could not find a way to flag as handled in the handler - so this always seems to result in an app shut down no matter what you do. So I do not think this is a lot of use.
但是我找不到在处理程序中标记为已处理的方法 - 因此无论您做什么,这似乎总是导致应用程序关闭。所以我认为这没有多大用处。
Better to handle Application.Current.DispatcherUnhandledExceptionand to test for CommunicationObjectFaultedException- as you can recover from that by just re-initializing your proxy - exactly as you did at initial connection. E.g:
更好地处理Application.Current.DispatcherUnhandledException和测试CommunicationObjectFaultedException- 因为您只需重新初始化代理即可从中恢复 - 就像您在初始连接时所做的那样。例如:
void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) {
if (e.Exception is CommunicationObjectFaultedException) { //|| e.Exception is InvalidOperationException) {
Reconnect();
e.Handled = true;
}
else {
MessageBox.Show(string.Format("An unexpected error has occured:\n{0}.\nThe application will close.", e.Exception));
Application.Current.Shutdown();
}
}
public bool Reconnect() {
bool ok = false;
MessageBoxResult result = MessageBox.Show("The connection to the server has been lost. Try to reconnect?", "Connection lost", MessageBoxButton.YesNo);
if (result == MessageBoxResult.Yes)
ok = Initialize();
if (!ok)
Application.Current.Shutdown();
}
where Initialize has your initial proxy instantiation/connection code.
其中 Initialize 具有您的初始代理实例化/连接代码。
In the code you posted above I suspect that you are handling DispatcherUnhandledExceptiontwice- by wiring a handler in xaml AND in code.
在您上面发布的代码中,我怀疑您正在处理DispatcherUnhandledException两次- 通过在 xaml 和代码中连接处理程序。

