C#: Elegant way to wrap method calls

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 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?

12
задан djskinner 11 April 2011 в 10:22
поделиться