C# 是否应同时使用AppDomain.UnhandledException和Application.DispatcherUnhandledException?

C# 是否应同时使用AppDomain.UnhandledException和Application.DispatcherUnhandledException?,c#,wpf,exception-handling,uncaught-exception,uncaughtexceptionhandler,C#,Wpf,Exception Handling,Uncaught Exception,Uncaughtexceptionhandler,在阅读了一些关于AppDomain.UnhandledException和Application.DispatcherUnhandledException之间差异的优秀文章之后,我似乎应该同时处理这两个问题。这是因为用户更可能从主UI线程引发的异常(即Application.DispatchernHandleException)中恢复。对吗 另外,我是否应该给用户一个机会,让其继续执行这两个程序,或者只执行Application.dispatchernhandledexception 下面的示例

在阅读了一些关于AppDomain.UnhandledException和Application.DispatcherUnhandledException之间差异的优秀文章之后,我似乎应该同时处理这两个问题。这是因为用户更可能从主UI线程引发的异常(即Application.DispatchernHandleException)中恢复。对吗

另外,我是否应该给用户一个机会,让其继续执行这两个程序,或者只执行Application.dispatchernhandledexception

下面的示例代码同时处理AppDomain.UnhandledException和Application.DispatcherUnhandledException,这两个代码都为用户提供了在异常情况下尝试继续的选项

[谢谢,下面的部分代码摘自其他答案]

App.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[修订]

/// <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;
}
//
///为Appdomain.UnhandledException添加调度程序
/// 
公共应用程序()
:base()
{
this.Dispatcher.UnhandledException+=OnDispatcherUnhandledException;
}
/// 
///捕获在主UI线程上引发的未处理异常并允许
///用户继续程序的选项。
///下面AppDomain.UnhandledException的OnDispatcherUnhandledException方法将处理任何线程引发的所有其他异常。
/// 
无效AppUI_DispatcherUnhandledException(对象发送方,System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
如果(e.Exception==null)
{
Application.Current.Shutdown();
返回;
}
string errorMessage=string.Format(“发生了应用程序错误。如果再次发生此错误,应用程序中似乎存在严重错误,您最好将其关闭。\n\n错误:{0}\n\n是否继续?\n(如果单击“是”,您将继续工作,如果单击“否”,应用程序将关闭)”,例如:Exception.Message;
//在此处插入代码以记录异常
if(MessageBox.Show(errorMessage,“应用程序用户界面错误”,MessageBoxButton.YesNoCancel,MessageBoxImage.Error)=MessageBoxResult.No)
{
如果(MessageBox.Show(“警告:应用程序将关闭。任何更改都不会保存!\n是否确实要关闭它?”,“关闭应用程序!”,MessageBoxButton.YesNoCancel,MessageBoxImage.WARNING)=MessageBoxResult.Yes)
{
Application.Current.Shutdown();
}
}
e、 已处理=正确;
}
/// 
///捕获主UI线程未引发的未处理异常。
///DispatcherUnandledException的上述AppUI_DispatcherUnandledException方法将仅处理主UI线程引发的异常。
///此方法捕获的未处理异常通常会终止运行时。
/// 
无效OnDispatcherUnhandledException(对象发送方,System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
string errorMessage=string.Format(“发生了应用程序错误。如果再次发生此错误,应用程序中似乎存在严重错误,您最好将其关闭。\n\n错误:{0}\n\n是否继续?\n(如果单击“是”,您将继续工作,如果单击“否”,应用程序将关闭)”,例如:Exception.Message;
//在此处插入代码以记录异常
if(MessageBox.Show(errorMessage,“应用程序未处理异常错误”,MessageBoxButton.YesNoCancel,MessageBoxImage.Error)==MessageBoxResult.No)
{
如果(MessageBox.Show(“警告:应用程序将关闭。任何更改都不会保存!\n是否确实要关闭它?”,“关闭应用程序!”,MessageBoxButton.YesNoCancel,MessageBoxImage.WARNING)=MessageBoxResult.Yes)
{
Application.Current.Shutdown();
}
}
e、 已处理=正确;
}

一个
AppDomain。未处理的异常
处理程序连接为:

AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
但是我找不到一种在处理程序中标记为handled的方法,所以不管你做什么,这似乎总是会导致应用程序关闭。所以我认为这没有多大用处

更好地处理
Application.Current.dispatchernhandledexception
和测试
communicationobjectfaultedxception
,因为您只需重新初始化代理即可从中恢复,与初始连接时完全相同。例如:

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();
}
其中Initialize包含初始代理实例化/连接代码

在您上面发布的代码中,我怀疑您正在通过在xaml和代码中连接处理程序来处理
DispatcherUnhandledException
两次
  • AppDomain.CurrentDomain.UnhandledException
    理论上捕获AppDomain所有线程上的所有异常。不过,我发现这是非常不可靠的
  • Application.Current.dispatchernhandledexception
    捕获UI线程上的所有异常。这似乎工作可靠,并将替换UI线程上的
    AppDomain.CurrentDomain.UnhandledException
    处理程序(优先)。使用
    e.Handled=true
    保持应用程序运行

  • 为了捕获其他线程上的异常(在最好的情况下,它们是在自己的线程上处理的),我发现System.Threading.Tasks.Task(仅.NET 4.0及更高版本)的维护性很低。使用方法
    .ContinueWith(…,TaskContinuationOptions.OnlyOnFaulted)
    处理任务中的异常。有关详细信息,请参阅我的答案


  • 我也不确定是否有可能同时处理UI线程的异常,但我怀疑可能会发生这种情况。这就是为什么它们的结尾都有e.handled=true的原因-这应该可以防止它被处理两次。您可以扩展一下
    。UnhandledException
    不可靠吗?