WCF サービスと通信する WPF アプリケーションがあります。async
現在、次のベースのパターンを使用して、ViewModels (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 Fault に変換される例外をスローした場合、すべてが期待どおりに機能します。
サービスのどこでもスローできる一般的な例外がいくつかあるため (たとえば、各 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 サービスを非同期的に呼び出すたびに)。
膨大な量のコードをリファクタリングしないようにするアイデアは役に立ちます。