WCF client-side error-handling

↘锁芯ラ 提交于 2019-11-29 10:19:23

You could use and modify the Exception Handling WCF Proxy Generator, more specifically, the base class that it uses. It's basic idea (check this description too) is to provide connection resilience by catching connection faults, and retrying the failed operation. As you can imagine, for this purpose it needs to be able to catch thrown exceptions, and also, it can inspect the result of calls.

The main functionality is given by the ExceptionHandlingProxyBase<T> base class, which you use instead of the ClientBase<T>. This base class has an Invoke method as follows, you'd need to modify that.

Simplified Invoke:

protected TResult Invoke<TResult>(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;
}  

You'll need to modify the throw targetEx.InnerException; part to handle the exceptions as you need, and obviously the resturn value shoudl also be inspected for your needs. Other then that you can leave the retry logic or throw it away if you don't expect connection problems. There is another variant of the Invoke for void return methods.

Oh, and by the way, it works with duplex channels as well, there is another base class for those.

If you don't want to use the generator (it might not even work in newer versions of VS), then you could just take the base class for example from here, and generate the actual implementation class with T4 from your service interface.

If the service isn't returning a true exception, but just a message, you probably want to add a ClientMessageInspector as a new client behavior. Please see: https://msdn.microsoft.com/en-us/library/ms733786.aspx

Shimmy

I've ended up using something based on the answers in this question.

It sticks to the generated client code, and allows invocation of the operations generically.

The code is incomplete, feel free to fork and edit it. Please notify me if you found any bugs or made any updates.

It's pretty bulky so I'll just share the usage code:

using (var proxy = new ClientProxy<MyServiceSoapClientChannel, MyServiceSoapChannel>())
{
  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");
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!