Search code examples
c#wcfwcf-client

WCF client-side error-handling


I'm consuming a clunky WCF server that occasionally throws various exceptions, and additionally returns some of its errors as string. I have no access to the server code at all.

I want to override the inner WCF-client request invocation method and handle all inner exceptions and hard-coded errors returned by the server and raise the Fault event if an error occurs, pseudo:

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

So that when I call myClient.GetHelloWorld(), it goes thru my overridden method.

How can this be achieved?
I know I don't have to use the generated client, but I don't want to re-implement all the contracts again, and I want to use the generated ClientBase subclass or at least its channel.
What I need is control over the inner request call method.

Update

I read this answer, and looks it's partially what I'm looking for, but I'm wondering if there is a way to attach an IErrorHandler to the consumer (client) code only, I want to add it to the ClientBase<TChannel> instance somehow.

Update

This article also looks very promising but it doesn't work. The applied attribute doesn't seem to take effect. I can't find a way to add IServiceBehavior to the client side.

Update

I tried attaching an IErrorHandler via IEndpointBehavior.ApplyClientBehavior calling:

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

(clientRuntime is a parameter), but exceptions are still thrown directly skipping MyErrorHandler.
ApplyDispatchBehavior isn't called at all.

Conclusion

I need to achieve two aspects:

  1. Wrap all exceptions that might occur during the lifetime of a BaseClient<TChannel> and decide whether to handle them or throw them on. This should take care of all operation (the service I'm consuming exposes few dozens)
  2. Parse all server-replies and throw exceptions for some of them, so they're forwarded as in statement 1.

Solution

  • 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");
    }