我有一个与 WCF 服务通信的 WPF 应用程序。我目前正在使用以下命令从我的 ViewModels 调用我的 WCF 服务(我正在使用 MVVM 模式)async
基于模式:
public async override void MyCommandImplementation()
{
using (var proxy = new MyProxy())
{
var something = await proxy.GetSomethingAsync();
this.MyProperty = something;
}
}
当我遵循 MVVM 模式时,我有ICommand
我的 ViewModel 公开的公共属性,因此关联的命令实现不会返回Task<T>
对象,因为它们就像事件处理程序。因此,异常处理实际上非常简单,即我可以使用以下模式捕获从 WCF 服务抛出的任何异常:
public async override void MyCommandImplementation()
{
try
{
using (var proxy = new MyProxy())
{
var something = await proxy.GetSomethingAsync();
}
}
catch (FaultException<MyFaultDetail> ex)
{
// Do something here
}
}
到目前为止,一切都很好,如果服务器抛出异常,由于自定义的 WCF 行为,该异常会自动转换为 SOAP 错误。
因为我有一些常见的异常,可以在我的服务中的任何地方抛出(例如每个 WCF 操作都可以抛出AuthenticationException
这将在客户端转换为FaultException<AuthenticationFaultDetail>
异常),我决定在应用程序的常见位置处理一些异常,即通过处理Application.DispatcherUnhandledException
事件。这很好用,我可以抓住我所有的FaultException<AuthenticationFaultDetail>
到处都有异常,向用户显示错误消息,并阻止应用程序退出:
private static void Application_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
// Exception handler that handles some common exceptions
// such as FaultException<AuthenticationFaultDetail>
if (GlobalExceptionHandler.HandleException(e.Exception))
{
// Expected exception, so we're fine
e.Handled = true;
}
else
{
// We're not fine. We couldn't handle the exception
// so we'll exit the application
// Log...etc.
}
}
一切都运转良好,因为FaultException
由于以下原因,被抛出到 UI 线程中async
模式和同步上下文切换之前/之后await
关键词。
我的问题是,除了我的 UI 线程之外,其他线程可能会引发其他异常,例如在以下情况下EndPointNotFoundException
扔在await proxy.GetSomethingAsync();
行(服务器端 WCF 服务关闭的情况)。
这些异常不会在Application.DispatcherUnhandledException
事件处理程序,因为它们不会在 UI 线程中抛出。我可以在AppDomain.UnhandledException
事件,但除了进行一些日志记录并退出应用程序之外,我无法做任何其他事情(基本上没有“e.Handled”之类的属性)。
所以我的问题是:如果在应用程序的某个位置发生异步 WCF 调用,我如何处理后台线程中引发的异常?
我现在能想到的最好的东西是这样的:
public class ExceptionHandler : IDisposable
{
public void HandleException(Exception ex)
{
// Do something clever here
}
public void Dispose()
{
// Do nothing here, I just want the 'using' syntactic sugar
}
}
...
public async override void MyCommandImplementation()
{
using (var handler = new ExceptionHandler())
{
try
{
using (var proxy = new MyProxy())
{
var something = await proxy.GetSomethingAsync();
}
}
catch (FaultException<MyFaultDetail> ex)
{
// Do something here
}
catch (Exception ex)
{
// For other exceptions in any thread
handler.HandleException(ex);
}
}
}
但这需要我重构大量代码(每次异步调用 Web 服务时)。
任何能让我做到的想法not重构大量代码会很有帮助。