tags:

views:

27

answers:

2

I've written an extension method for use with WCF services that keeps all the disposal and exception handling logic in one place. The method is as follows:

public static TResult CallMethod<TChannel, TResult>(
    this ClientBase<TChannel> proxy,
    Func<TResult> func) where TChannel : class
{
    proxy.ThrowIfNull("proxy");
    func.ThrowIfNull("func");

    try
    {
        // set client credentials
        return func();
    }
    finally
    {
        if (proxy != null)
        {
            try
            {
                if (proxy.State != CommunicationState.Faulted)
                {
                    proxy.Close();
                }
                else
                {
                    proxy.Abort();
                }
            }
            catch (CommunicationException)
            {
                proxy.Abort();
            }
            catch (TimeoutException)
            {
                proxy.Abort();
            }
            catch (Exception)
            {
                proxy.Abort();
                throw;
            }
        }
    }
}

The method will be used like this:

public int CreateBusinessObject(BusinessObject item)
{
    MyServiceClient proxy = new MyServiceClient();
    return proxy.CallMethod(() => proxy.CreateBusinessObject(item));
}

My question really is whether this would be better as a static method which creates the service proxy? I'm slightly worried about my current implementation. Should the construction of the proxy be inside the try/catch? My current understanding is that if the constructor fails, there is nothing to dispose of anyway.

+1  A: 

I usually add the following to my service facades to interact with the service (I'm not sure an extension method helps a lot here but it's a matter of taste).

private delegate void ServiceAction(ServiceClient proxy);

private void PerformServiceAction(ServiceAction action)
{
    ServiceClient proxy = new ServiceClient();

    try
    {
        // set client credentials  
        action(proxy);
    }
    finally
    {
        if (proxy != null)
        {
            try
            {
                if (proxy.State != CommunicationState.Faulted)
                {
                    proxy.Close();
                }
                else
                {
                    proxy.Abort();
                }
            }
            catch (CommunicationException)
            {
                proxy.Abort();
            }
            catch (TimeoutException)
            {
                proxy.Abort();
            }
            catch (Exception)
            {
                proxy.Abort();
                throw;
            }
        }
    }
}

which can be invoked like this:

return serviceFacade.PerformServiceAction((proxy) => proxy.CreateBusinessObject(item));  
vc 74
+2  A: 

If the constructor fails, the entire object is in an invalid state. You should not be worried about disposing in this case.

A nice test for this is what would happen when you execute the following:

class Program
{
    static void Main(string[] args)
    {
        using (new TestClass())
        {
            Console.WriteLine("In using");
        }
    }

    class TestClass : IDisposable
    {
        public TestClass()
        {
            throw new Exception();
        }

        public void Dispose()
        {
            Console.WriteLine("Disposed");
        }
    }
}

The result is that the Disposing never gets reached. This is what happens when the constructor fails.

Pieter
Good point. I should have known do try something like this. Thanks.
Lemon Jelly