using
を実装するリソースを使用する標準的な方法であるため、ブロック内で WCF サービス クライアントをインスタンス化するのが好きIDisposable
です。
using (var client = new SomeWCFServiceClient())
{
//Do something with the client
}
ただし、この MSDN の記事で説明されているように、WCF クライアントをusing
ブロックでラップすると、クライアントが障害状態のままになるエラー (タイムアウトや通信の問題など) を隠すことができます。簡単にDispose()
言うと、 が呼び出されると、クライアントのClose()
メソッドが起動しますが、エラーが発生した状態であるため、エラーがスローされます。元の例外は、2 番目の例外によってマスクされます。良くない。
MSDN の記事で推奨されている回避策は、using
ブロックの使用を完全に回避し、代わりにクライアントをインスタンス化して、次のように使用することです。
try
{
...
client.Close();
}
catch (CommunicationException e)
{
...
client.Abort();
}
catch (TimeoutException e)
{
...
client.Abort();
}
catch (Exception e)
{
...
client.Abort();
throw;
}
ブロックと比べると、using
それは醜いと思います。また、クライアントが必要になるたびに大量のコードを記述する必要があります。
幸いなことに、(現在は廃止された) IServiceOriented ブログで、このような回避策をいくつか見つけました。次から始めます。
public delegate void UseServiceDelegate<T>(T proxy);
public static class Service<T>
{
public static ChannelFactory<T> _channelFactory = new ChannelFactory<T>("");
public static void Use(UseServiceDelegate<T> codeBlock)
{
IClientChannel proxy = (IClientChannel)_channelFactory.CreateChannel();
bool success = false;
try
{
codeBlock((T)proxy);
proxy.Close();
success = true;
}
finally
{
if (!success)
{
proxy.Abort();
}
}
}
}
次に許可します:
Service<IOrderService>.Use(orderService =>
{
orderService.PlaceOrder(request);
});
using
それも悪くないのですが、ブロックほど表現力がなく分かりやすいとは思いません。
私が現在使用しようとしている回避策は、blog.davidbarret.netで最初に読んだものです。基本的に、クライアントのDispose()
メソッドはどこで使用してもオーバーライドします。何かのようなもの:
public partial class SomeWCFServiceClient : IDisposable
{
void IDisposable.Dispose()
{
if (this.State == CommunicationState.Faulted)
{
this.Abort();
}
else
{
this.Close();
}
}
}
using
これにより、フォルト状態の例外をマスクする危険なしに、ブロックを再び許可できるようです。
では、これらの回避策を使用して注意しなければならない問題は他にありますか? 誰かがより良いものを思いつきましたか?