TIP: Closing your WCF Connections properly

In a previous tip, you looked at how you could use ChannelFactory or Proxy Classes to talk to a WCF service. Now you can have a look at how to properly close of these connections.

If you've used Visual Studio to generate a WCF proxy class for one of your WCF services, go on and have a look at it now. In it, have a look at the generated client class:

public partial class StockServiceClient : System.ServiceModel.ClientBase<StockService.IStockService>, StockService.IStockService {
...

The client that you use in your main code inherits from ClientBase<>. Looking at ClientBase on MSDN, you see that it implements IDisposable. As with most other classes implementing IDisposable, it is tempting to use the C# using statement for your WCF clients.

//It's tempting, but don't do this:
using(StockService.StockServiceClient client = new StockService.StockServiceClient(
              "StockBasicHttpEndpoint", stockServiceUrl))
{
client.GetStockIdByName("MSFT");
}

And as you know, the using block will automatically call client.Dispose() when it's done. There's a problem with it though — with ClientBase, the Dispose() method makes a call to Close(). When the ClientBase's Close() method is called, a web service call actually goes out to the WCF service, informing it that the connection session is no longer required. This appears counter-intuitive, but it was done by design. The problem with this mechanism is that when the Close() method is called, an exception can be thrown. After all, it involves yet another network call to a web service. It's for this reason that the using statement isn't recommended with WCF clients.

Instead, you should attempt to Close() it in a try-catch block, with the catch block performing an Abort()

//Call your web service as usual.
StockService.StockServiceClient client = new StockService.StockServiceClient(
              "StockBasicHttpEndpoint", stockServiceUrl);

string StockId = client.GetStockIdByName("MSFT");

//Done with the service, let's close it.
try
{
   if (client.State != System.ServiceModel.CommunicationState.Faulted)
   {
      client.Close();
   }
}
catch (Exception ex)
{
   client.Abort();
}

The same thing applies to your ChannelFactory, if you use one — and the code to close it is exactly the same.
//Create channel from factory
ChannelFactory channel =
   new ChannelFactory<IService1>("bindingName");
IService1 client = channel.CreateChannel();

client.DoWork();

//Done with the service, let's close it.
try
{
   if (client.State != System.ServiceModel.CommunicationState.Faulted)
   {
      client.Close();
   }
}
catch (Exception ex)
{
   client.Abort();
}

So the points made here, very briefly, are

  • Don't use 'using' with your WCF client classes
  • .Close() the client in a try-catch block and .Abort() it if an exception occurs.


About the Author

SM Altaf

Mendhak is a web developer and a Microsoft MVP who works with ASP.NET and PHP among the usual array[] of web technologies. He is also rumored to be a three eyed frog, but the evidence is lacking. He can be contacted via his website, www.mendhak.com.


Comments

  • Is this still true in 4.5

    Posted by Brian Wagg on 02/02/2016 01:40pm

    Is this still true in .NET 4.5? I've read a few places that WCF will call dispose for you if you are using perCall. But it doesn't go into details as to whether it is calling dispose on your client proxy or on other objects it may have had to create when communicating with the server. Any insight would be appreciated. An example of where it is stated: http://www.codeguru.com/csharp/csharp/net30/article.php/c15941/TIP-Closing-your-WCF-Connections-properly.htm

    Reply
  • I don't think so either!

    Posted by Mark on 04/17/2012 07:19am

    You are better off aborting the object in the 'Finally' part of the try-ctach. In your example you won't be able to abort unless exception is thrown. What if no exception is thrown but the transaction lasts forever? You then have to realy on yout timeout quota, which effectively (in the case of a large app) may end up in multiple sessions lingering and waiting to be disposed off. Please remove this post - it is nto right and may be confusing for some readers. Regards.

    Reply
  • No, I don't think so.

    Posted by JerryNixon on 03/09/2011 03:12pm

    1. With your TIP the method call (cal named it DoWork()) may fail, causing the flow to exit the method and bypass the possibility of the Abort() call in your catch { client.Abort(); }. 2. WIth your TIP the method call may pass, but the state may be faulted, but Abort() cannot be called because an exception is required. It seems to me that you should: 1. Move the method call into your try { } block. 2. Remove the (State != Faulted) if statement. Are you sure about your suggestion here?

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date