2

My application calls a web-service using WCF. The call can fail for various reasons:

  • fault
  • timeout
  • connection lost
  • ...

I want to log all such errors. Instead of wrapping every call in a try-catch, I want to do this in one place for all web-service calls in the entire application.

Unfortunately, an IClientMessageInspector does not get called for timeouts and connection failures. Is there a WCF extensibility point that I can use to centrally take note of all exceptions?

Notice, that I do not just want to log errors as text like WCF Tracing does it. I want to log:

  • ServiceName
  • MethodName
  • Duration
  • Exception.ToString()

I am open to workarounds.

usr
  • 168,620
  • 35
  • 240
  • 369
  • Can you provide a code-sample example of one of your calls? Are you currently creating, calling, and disposing of your service per call? – Jaime Torres Jul 10 '12 at 16:38
  • @JTorres, I instantiate the service proxy once per "unit of work" which comes out at 1-10 calls per instance. This means that I cannot re-use this place to add an exception handler. – usr Jul 10 '12 at 16:52
  • I believe I understand what you're saying (create a service references, call 1 to 10 methods on said service, destroy reference). What you are attempting to do is add some form of error handling around these, without actually writing the error handling in code, because (1) that makes code look fugly and (2) that's a lot of recoding to do. Unfortunately, I believe you are pretty stuck. The closest thing to an "extension" solution I could think of is to use an AOP utility like PostSharp and decorate your calls with the appropriate aspect. @Trey Combs's solution would make for better design. – Jaime Torres Jul 10 '12 at 17:05

1 Answers1

1

I am not aware of an extensibility point, but I can provide a workaround that we have used. Basically, we created a "proxy" that all service calls were made through. Below is the proxy and an example of its use.

/// <summary>
/// Proxy for executing generic service methods
/// </summary>
public class ServiceProxy
{
    /// <summary>
    /// Execute service method and get return value
    /// </summary>
    /// <typeparam name="C">Type of service</typeparam>
    /// <typeparam name="T">Type of return value</typeparam>
    /// <param name="action">Delegate for implementing the service method</param>
    /// <returns>Object of type T</returns>
    public static T Execute<C, T>(Func<C, T> action) where C : class, ICommunicationObject, new()
    {
        C svc = null;

        T result = default(T);

        try
        {
            svc = new C();

            result = action.Invoke(svc);

            svc.Close();
        }
        catch (FaultException ex)
        {
            // Logging goes here
            // Service Name: svc.GetType().Name
            // Method Name: action.Method.Name
            // Duration: You could note the time before/after the service call and calculate the difference
            // Exception: ex.Reason.ToString()

            if (svc != null)
            {
                svc.Abort();
            }

            throw;
        }
        catch (Exception ex)
        {
            // Logging goes here

            if (svc != null)
            {
                svc.Abort();
            }

            throw;
        }

        return result;
    }
}

And an example of its use:

var result = ServiceProxy.Execute<MyServiceClient, MyReturnType>
(
    svc => svc.GetSomething(someId)
);
Trey Combs
  • 710
  • 5
  • 10
  • This solution would work, but I don't like changing all about 100 service calls in the entire application... And I don't want to re-test all of them. I really seek some kind of central solution. – usr Jul 10 '12 at 16:23
  • 1
    This would be a great central solution, had you started with it. It provides fairly robust flexibility down the line, but may not be feasible to implement now that you're fairly far down the path of development. That being said, save for a miraculous handler/behavior I'm not aware of, I don't believe any solution is going to be pain-free at this point. – Jaime Torres Jul 10 '12 at 17:08