我喜欢在一个using块中实例化WCF服务客户端,因为这几乎是使用实现资源的标准方法IDisposable:
using
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()无论您在何处使用它,都将覆盖其方法。就像是:
Dispose()
public partial class SomeWCFServiceClient : IDisposable { void IDisposable.Dispose() { if (this.State == CommunicationState.Faulted) { this.Abort(); } else { this.Close(); } } }
这似乎能够using再次允许该块而没有掩盖故障状态异常的危险。
因此,使用这些解决方法是否还有其他陷阱?有没有人提出更好的建议?
实际上,尽管我写了博客(请参阅Luke的答案),但我认为这比我的IDisposable包装更好。典型代码:
Service<IOrderService>.Use(orderService=> { orderService.PlaceOrder(request); });
(按评论编辑)
由于Usereturn void,处理返回值的最简单方法是通过捕获的变量:
Use
int newOrderId = 0; // need a value for definite assignment Service<IOrderService>.Use(orderService=> { newOrderId = orderService.PlaceOrder(request); }); Console.WriteLine(newOrderId); // should be updated