IDisposable and WCF

Posted by: Steven Smith, on 09 Feb 2009 | View original | Bookmarked: 0 time(s)

Recently weve been separating our monolithic application into smaller systems which communicate via services.  Were using WCF for this communication, and one of the things that weve 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 dont think resources should be marked IDisposable if you cant simply use the using() statement.  The issue with the case of WCFs clients 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 theyre still compatible with using().

Heres 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.  Heres 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.  Heres the code that you shouldnt use because WCF doesnt work with it:

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

Heres the code that youre 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;
}

Isnt 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.  Im not sure at that point that youre 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 heres 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 *dont* 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 werent 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; Im 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).

Category: WCF | Other Posts: View all posts by this blogger | Report as irrelevant | View bloggers stats | Views: 2840 | Hits: 18

Similar Posts

  • Discusses WCFs extensibility points used in DI IInstanceProvider interface and contract behaviors. The author also shows how to extend a commerce application with a WCF-based service. more
  • Simplifying the WcfService Connection - The WcfServiceDataProvider control more
  • Simplifying the WCF Service Connection - The WcfServiceDataProvider control more
  • WcfTestClient with Windows Azure more
  • Create a SQL Azure CRUD Application with Telerik OpenAccess and the WCF Wizard more
  • Telerik OpenAccess WCF Wizard: How-to Video #5- ATOMPub Property Selector more
  • Business Apps Example for Silverlight 3 RTM and .NET RIA Services July Update Summary more
  • WCF 4: Higher Default Throttling Settings for WCF Services more
  • Using FindBySubjectDistinguishedName more
  • Disposing a WCF Proxy more

News Categories

.NET | Agile | Ajax | Architecture | ASP.NET | BizTalk | C# | Certification | Data | DataGrid | DataSet | Debugger | DotNetNuke | Events | GridView | IIS | Indigo | JavaScript | Mobile | Mono | Patterns and Practices | Performance | Podcast | Refactor | Regex | Security | Sharepoint | Silverlight | Smart Client Applications | Software | SQL | VB.NET | Visual Studio | W3 | WCF | WinFx | WPF | WSE | XAML | XLinq | XML | XSD