我喜欢在using
块中实例化我的WCF服务客户端,因为这几乎是使用实现IDisposable
的资源的标准方式:
using (var client = new SomeWCFServiceClient())
{
//Do something with the client
}
但是,正如这篇MSDN文章中所指出的,将WCF客户端包装在using
块中可以掩盖任何导致客户端处于故障状态的错误(如超时或通信问题)。长话短说,当调用Dispose()
时,客户端的Close()
方法会触发,但会抛出一个错误,因为它处于故障状态。然后,原始异常被第二个异常掩盖。不好的。
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
块,而不会有掩盖错误状态异常的危险。
那么,使用这些变通方法还有其他需要注意的问题吗?有没有人想出更好的办法?