WCF客户端error handling

我正在消耗一个笨重的WCF服务器,它偶尔会抛出各种exception,并且还会将一些错误作为string返回。 我根本无法访问服务器代码。

我想覆盖内部WCF客户端请求调用方法并处理服务器返回的所有内部exception和硬编码错误,并在发生错误时引发Fault事件,伪:

 class MyClient : MyServiceSoapClient { protected override OnInvoke() { object result; try { result = base.OnInvoke(); if(result == "Error") { //raise fault event } catch { //raise fault event } } } 

因此,当我调用myClient.GetHelloWorld() ,它会通过我的重写方法。

怎么能实现这一目标?
我知道我不必使用生成的客户端,但我不想再次重新实现所有合同,我想使用生成的ClientBase子类或至少使用它的通道。
我需要的是控制内部请求调用方法。

更新

我读了这个答案 ,看起来它部分是我正在寻找的,但我想知道是否有办法将IErrorHandler仅附加到消费者(客户端)代码,我想将它添加到ClientBase实例不知何故。

更新

这篇文章看起来很有希望,但它不起作用。 应用的属性似乎没有生效。 我找不到将IServiceBehavior添加到客户端的方法。

更新

我尝试通过IEndpointBehavior.ApplyClientBehavior调用附加IEndpointBehavior.ApplyClientBehavior

 public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { clientRuntime.CallbackDispatchRuntime.ChannelDispatcher.ErrorHandlers .Add(new ErrorHandler()); } 

clientRuntime是一个参数),但仍然会直接跳过exception跳过MyErrorHandler
ApplyDispatchBehavior不调用ApplyDispatchBehavior

结论

我需要实现两个方面:

  1. 包装在BaseClient生命周期内可能发生的所有exception,并决定是处理它们还是将它们抛出。 这应该照顾所有操作(我正在消耗的服务暴露了几十个)
  2. 解析所有服务器回复并为其中一些回复抛出exception,因此它们将在语句1中转发。

您可以使用和修改exception处理WCF代理生成器 ,更具体地说,它是使用它的基类。 它的基本思想(检查此描述 )是通过捕获连接故障并重试失败的操作来提供连接弹性。 可以想象,为此目的,它需要能够捕获抛出的exception,并且还可以检查调用的结果。

主要function由ExceptionHandlingProxyBase基类提供,您可以使用它来代替ClientBase 。 这个基类有一个Invoke方法,如下所示,你需要修改它。

简化Invoke

 protected TResult Invoke(string operationName, params object[] parameters) { this.Open(); MethodInfo methodInfo = GetMethod(operationName); TResult result = default(TResult); try { this.m_proxyRecreationLock.WaitOne(this.m_proxyRecreationLockWait); result = (TResult)methodInfo.Invoke(m_channel, parameters); } catch (TargetInvocationException targetEx) // Invoke() always throws this type { CommunicationException commEx = targetEx.InnerException as CommunicationException; if (commEx == null) { throw targetEx.InnerException; // not a communication exception, throw it } FaultException faultEx = commEx as FaultException; if (faultEx != null) { throw targetEx.InnerException; // the service threw a fault, throw it } //... Retry logic } return result; } 

你需要修改throw targetEx.InnerException; 根据需要处理exception的部分,显然还要根据您的需要检查resturn值。 除此之外,如果您不期望连接问题,您可以保留重试逻辑或将其丢弃。 Invoke for void返回方法还有另一种变体。

哦,顺便说一句,它也适用于双工通道,还有另一个基类。

如果您不想使用生成器(它甚至可能不适用于较新版本的VS),那么您可以从此处获取基类,并从服务接口生成带有T4的实际实现类。

如果服务未返回真正的exception,而只返回消息,则可能需要将ClientMessageInspector添加为新的客户端行为。 请参阅: https : //msdn.microsoft.com/en-us/library/ms733786.aspx

我最终根据这个问题的答案使用了一些东西。

它坚持生成的客户端代码,并允许一般调用操作。

代码不完整,随意分叉和编辑它。 如果您发现任何错误或进行任何更新,请通知我。

它非常笨重,所以我只是分享使用代码:

 using (var proxy = new ClientProxy()) { client.Exception += (sender, eventArgs) => { //All the exceptions will get here, can be customized by overriding ClientProxy. Console.WriteLine($@"A '{eventArgs.Exception.GetType()}' occurred during operation '{eventArgs.Operation.Method.Name}'."); eventArgs.Handled = true; }; client.Invoke(client.Client.MyOperation, "arg1", "arg2"); }