Steve Smith's Blog

Musings on Software and the Developer Community

IDisposable and WCF

Recently we’ve been separating our monolithic application into smaller systems which communicate via services.  We’re using WCF for this communication, and one of the things that we’ve quickly noticed is that WCF is, for whatever reason, not compatible with the usual best practice of wrapping IDisposable objects with a using() {…} block.  Personally, I don’t think resources should be marked IDisposable if you can’t simply use the using() statement.  The issue with the case of WCF’s client’s is that the call to Close() may throw an exception (a network error).  I have to believe that other disposable resources might also run into problems when cleaning up their connections, but somehow they’re still compatible with using().

Here’s an MSDN article showing the problem quite well:

Avoiding Problems with the Using Statement

If you do go the using() route, and errors occur, they end up throwing from the closing brace of the using() block, and being rather difficult to diagnose.  Here’s an example of such a WCF error with a using() statement.

It also includes the code for how to clean up after services correctly in light of the fact that they may blow up due to network errors.  Here’s the code that you shouldn’t use because WCF doesn’t work with it:

using (var myClient = new ServiceClient())
{
  int value = myClient.GetSomeValue();
}

Here’s the code that you’re forced to use instead:

var myClient = new ServiceClient();
try
{
  int value = myClient.GetSomeValue();
  // ...
  myClient.Close();
}
catch (CommunicationException e)
{
  // ...
  client.Abort();
}
catch (TimeoutException e)
{
  // ...
  client.Abort();
}
catch (Exception e)
{
  // ...
  client.Abort();
  throw;
}

Isn’t that nice and clean?  Of course you can add it as an Extension Method to your ServiceClient.  If you do that, then you simply need to remember to use a finally block to call the code.  I’m not sure at that point that you’re any further ahead than if you just used the using() statement to begin with, but at least it eliminates the problem of having an exception thrown on the closing brace of the using block  and keeps the total amount of plumbing code that needs written to a minimum.  Your code then might look like this:

var myClient = new ServiceClient();
try
{
  int someValue = myClient.GetSomeValue();
}
finally
{
  myClient.CloseConnection(); // extension method
}

 

And here’s the extension method:

public static class Extensions
    {
        /// <summary>
        /// Safely closes a service client connection.
        /// </summary>
        /// <param name="myServiceClient">The client connection to close.</param>
        public static void CloseConnection(this ICommunicationObject myServiceClient)
        {
            if (myServiceClient.State != CommunicationState.Opened)
            {
                return;
            }
 
            try
            {
                myServiceClient.Close();
            }
            catch (CommunicationException ex)
            {
                Debug.Print(ex.ToString());
                myServiceClient.Abort();
            }
            catch (TimeoutException ex)
            {
                Debug.Print(ex.ToString());
                myServiceClient.Abort();
            }
            catch (Exception ex)
            {
                Debug.Print(ex.ToString());
                myServiceClient.Abort();
                throw;
            }
        }
    }

This method simply logs any exceptions via Debug.Print, but obviously you can adjust that to suit your exception handling procedures.

Note that if you *don’t* clean up these connections, they will come back to bite you.  One of our developers ran into an issue with our suite of integration tests for these services where they would work fine individually, but if you ran more than 10 of them, it would get real slow and start failing.  Turns out they weren’t being closed so after enough of them were opened, the rest would time out waiting for an open connection.  Yet another reason why testing pays off; I’m sure it would have been much harder for us to diagnose why our application was randomly slowing down and not working periodically (especially as this is for an unattended batch process).

    kick it on DotNetKicks.com

Monday, 09 February 2009

Comments

 avatar

Lars Wilhelmsen said on 09 Feb 2009 at 2:08 PM

Hi,

No need for a extension method, the generated client proxy is marked as partial, so you can add a .Dispose() method that takes the current State into account (and either .Close() or .Abort() the underlying channel.

Best regards,

Lars Wilhelmsen

Connected Systems MVP


ssmith avatar

ssmith said on 09 Feb 2009 at 3:30 PM

@Lars,

That's correct, but then I would have to do that for every generated proxy, whereas the more generic extension method can be used more broadly (and referenced from a utility assembly, if desired, rather than compiled into the proxy). Right?


 avatar

Tim Rayburn said on 09 Feb 2009 at 11:59 PM

You are correct that extending the class via partial would require you to do this for every single client. On the other hand, you could take the extension method move one step further than you did. This code snippet has enough Generics to make even my head spin, but works, and allows a quick lambda that returns your desired result to execute, strongly typed the entire way. The key here is the use of a Generic constraint.

public static TResult SafeExecution<TExtension, TResult>

(this TExtension myServiceClient,

Func<TExtension, TResult> serviceAction)

where TExtension : ICommunicationObject

{

TResult outValue;

try

{

outValue = serviceAction.Invoke(myServiceClient);

}

finally

{

myServiceClient.CloseConnection();

}

return outValue;

}

Anyway, enjoy!

Tim Rayburn

(also a) Connected Systems MVP


 avatar

Delf said on 10 Feb 2009 at 5:53 AM

Instead of repeating myServiceClient.Abort(); in each catch section, use it inside the finally one.


 avatar

barryd said on 11 Feb 2009 at 3:37 PM

Jesse Ezell has a rather nifty lambda alternative at

www.iserviceoriented.com/.../Indisposable+-+

So you get the benefit of the close whern it falls out of scope :)


 avatar

Damien McGivern said on 12 Feb 2009 at 9:25 AM

There is no need for the scope of service proxy to extend outside out of the code block so I use the following code which is based on Jesse Ezell's post mentioned above.

public static void Using<ServiceT>(Action<ServiceT> action)

where ServiceT : ICommunicationObject, new()

{

var service = new ServiceT();

bool success = false ;

try

{

action(service);

service.Close();

success = true;

}

finally

{

if(!success)

{

service.Abort();

}

}

}


 avatar

consacepo said on 23 Aug 2009 at 2:53 PM

You are correct that extending the class via partial would require you to do this for every single client. On the other hand, you could take the extension method move one step further than you did. This code snippet has enough Generics to make even my head spin, but works, and allows a quick lambda that returns your desired result to execute, strongly typed the entire way. The key here is the use of a Generic constraint.

<a href="http://consacepo.blogspot.com">consacepo</a>


 avatar

consacepo said on 23 Aug 2009 at 2:54 PM

No need for a extension method, the generated client proxy is marked as partial, so you can add a .Dispose() method that takes the current State into account (and either .Close() or .Abort() the underlying channel.


 avatar

developer said on 28 Aug 2009 at 8:13 AM

We are making WCF calls using the following Code.

// In generated Proxy we have..

public static ICustomer Customer

{

get

{

ChannelFactory<ICustomer> factory = new ChannelFactory<ICustomer>("Customer");

factory.Endpoint.Behaviors.Add((System.ServiceModel.Description.IEndpointBehavior)new ClientMessageInjector());

ICustomer channel = factory.CreateChannel();

return channel;

}

}

and we have Service Proxy class which has the methods like

public static Datatable GetCustomerDetails(int id)

{

return Services.Customer.GetCustomerDetails(id);

}

Recently we found out that we need to "Close" the wcf connection and we are trying to find out away to do this without asking our developers to change too much of their code.

Any Ideas ?