C#: Elegant way to wrap method calls

djskinner picture djskinner · Apr 11, 2011 · Viewed 10.8k times · Source

Apologies for the fairly ambiguous title but what I'm trying to achieve is probably better stated in code.

I have a WCF client. When I'm calling methods I would like to wrap each call in some error handling code. So, instead of exposing the methods directly, I've created the following helper function on the client class:

    public T HandleServiceCall<T>(Func<IApplicationService, T> serviceMethod)
    {
        try
        {
            return serviceMethod(decorator);
        }
        [...]
    }

And the client code uses it like this:

service.HandleServiceCall(channel => channel.Ping("Hello"));

And the call to Ping gets nicely wrapped in some logic that will try to handle any errors.

This works great except that I now have a requirement to know which methods are actually being called on the service. Initially , I was hoping to just inspect the Func<IApplicationService, T> using Expression trees but didn't get very far.

Finally, I settled on a Decorator pattern:

    public T HandleServiceCall<T>(Func<IApplicationService, T> serviceMethod)
    {
        var decorator = new ServiceCallDecorator(client.ServiceChannel);
        try
        {
            return serviceMethod(decorator);
        }
        [...]
        finally
        {
            if (decorator.PingWasCalled)
            {
                Console.Writeline("I know that Ping was called")
            }
        }
    }

And the Decorator itself:

    private class ServiceCallDecorator : IApplicationService
    {
        private readonly IApplicationService service;

        public ServiceCallDecorator(IApplicationService service)
        {
            this.service = service;
            this.PingWasCalled = new Nullable<bool>();
        }

        public bool? PingWasCalled
        {
            get;
            private set;
        }

        public ServiceResponse<bool> Ping(string message)
        {
            PingWasCalled = true;
            return service.Ping(message);
        }
    }

It's really clunky and quite a lot of code. Is there a more elegant way of doing this?

Answer

Richard Friend picture Richard Friend · Apr 11, 2011

You could use an Expression, then inspect the body.

Something like

public T HandleServiceCall<T>(Expression<Func<IApplicationService, T>> serviceMethod)     
{         
    try         
    {          
        var func = serviceMethod.Compile();
        string body = serviceMethod.Body.ToString();
        return func(new ConcreteAppService()); 
    }        
    catch(Exception ex)
    {
        ...     
              }
}