none
Hiding the try/close/catch/abort WCF client pattern

    Question

  • As from this thread: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=855018&SiteID=1

    The right pattern to using a client channel is like this:

    Client c = new Client(); // Or creation via factory
    try
    {
      c.Foo();
      c.Close();
    }
    catch
    {
      c.Abort();
      throw;
    }


    This is really annoying to have sprinkled throughout all your code. So, I wrote a helper function:

    public static void UseServiceClient<T>(Action<T> action)

    {

      ChannelFactory<T> factory = new ChannelFactory<T>("*");

      T client = factory.CreateChannel();

      try

      {

          action(client);

          ((IClientChannel)client).Close();

          factory.Close();

      }

      catch

      {

          ((IClientChannel)client).Abort();

          factory.Abort();

          throw;

      }

    }

    This allows the callers of functions to call services like this:

    UseServiceClient<ISomeService>(delegate(ISomeService client)

    {

      client.Foo();

    });

    Yes, having to specify the ISomeService type twice is silly, but for some reason the C# compiler can't infer from anonymous methods... moot point once C# 3 arrives anyways. The caller can add try/catch to get specific faults like normal.

    Any ideas/improvements on this? It'd be real nice if ChannelFactory had something like this built in (or if somehow the WCF API allowed a more friendly calling pattern).

    Thanks!
    Michael

    Tuesday, January 16, 2007 6:32 PM

Answers

  • Your idea will work well.  There are a couple variations I want to point out which I'm sure you've considered, but which may be interesting to others reading the thread.

    #1:

    Rather than catch, you can use finally, as in

    try
    {
        action(client);
        client.Close();
    }
    finally
    {
        client.Abort();
    }

    This pattern has the advantage of not interrupting the exception stack unwinding process.  Catching and rethrowing will slightly complicate debugging (uncaught exceptions will appear to have been thrown by UseServiceClient) and uses more CPU.  On the other hand, the finally will run even when no exception occurs.  Although calling Abort is harmless after calling Close, it uses some CPU too.  The extra Abort call can be avoided by setting a flag:

    bool success = false;
    try
    {
        action(client);
        client.Close();
        success = true;
    }
    finally
    {
        if (!success)
        {
            client.Abort();
        }
    }

    Readers familiar with MSIL will recognize the above as being reminiscent of a 'fault' block.  Fault blocks are finally blocks which only exceute when the try block throws an exception.  They can't be used from C#, but they can be simulated using a finally block with a boolean 'success' flag as above.

    Sunday, March 04, 2007 10:47 PM

All replies

  • Your idea will work well.  There are a couple variations I want to point out which I'm sure you've considered, but which may be interesting to others reading the thread.

    #1:

    Rather than catch, you can use finally, as in

    try
    {
        action(client);
        client.Close();
    }
    finally
    {
        client.Abort();
    }

    This pattern has the advantage of not interrupting the exception stack unwinding process.  Catching and rethrowing will slightly complicate debugging (uncaught exceptions will appear to have been thrown by UseServiceClient) and uses more CPU.  On the other hand, the finally will run even when no exception occurs.  Although calling Abort is harmless after calling Close, it uses some CPU too.  The extra Abort call can be avoided by setting a flag:

    bool success = false;
    try
    {
        action(client);
        client.Close();
        success = true;
    }
    finally
    {
        if (!success)
        {
            client.Abort();
        }
    }

    Readers familiar with MSIL will recognize the above as being reminiscent of a 'fault' block.  Fault blocks are finally blocks which only exceute when the try block throws an exception.  They can't be used from C#, but they can be simulated using a finally block with a boolean 'success' flag as above.

    Sunday, March 04, 2007 10:47 PM
  • Thanks, you're absolutely right about the finally being better, I'm not sure what I was thinking :S. I'm hoping with the newer languages (C# 3 in particular), more patterns will be built-in to the framework libraries...

    I also added a ChannelFactory cache to my code -- is there any danger in having channel factories sitting around?

    Thanks!
    -Michael

    Sunday, March 04, 2007 11:05 PM
  • There's no problem keeping ChannelFactories around, and it's a good idea to cache them.  ChannelFactories are relatively expensive to create.
    Monday, March 05, 2007 12:01 AM
  • Awesome, thanks for the help!
    -Michael

    Monday, March 05, 2007 1:10 AM
  • Michael,
     
    This has been a great help to me in my search to create a generic way to encapsulate all the try...catch..finally stuff that is necessary to surround each service call. I am extending your example to include the ability to retry a function call a specified number of times, and I am also looking at caching the ChannelFactory's (as you mention above) to improve performance.
     
    Any chance you could post your completed class with caching?
     
    Thanks,
    Will.
    Monday, July 28, 2008 8:18 PM
  • Michael, Will. I know it's been a while since your posts, but have you done any work in this area? In particular, I am looking for a ChannelFactory caching and having N numbers of retries. This post has been indexed well in all search engines. Please post your code if possible for the community benefit.

    Thank you in advance,

     

     

     

    Monday, January 31, 2011 10:25 PM