我有一个与 WCF 服务通信的 WPF 应用程序。我目前正在使用以下async
基于模式从我的 ViewModel(我正在使用 MVVM 模式)调用我的 WCF 服务:
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 服务时)。
任何能让我不重构大量代码的想法都会有所帮助。