Blog

  • Home /
  • Blog /
  • Exploring WCF - The Close vs Abort confusion

Exploring WCF - The Close vs Abort confusion

May 9, 2007

In my journey to explore the Windows Communication Foundation, I came across an issue that confused me at first but actually made some sense after spending half a day figuring things out.

In order to understand to try out fault contracts in WCF, I created a service like the following:

[ServiceContract()]
public interface IFaultService
{
    [OperationContract]
    [FaultContract(typeof(InvalidOperationException))]
    String CalculateSomeStuff();
}

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class FaultService : IFaultService
{
    public String CalculateSomeStuff() 
    {
        throw new InvalidOperationException(
            "Invalid operation, dude.");
    }
}

After generating a proxy with svcutil, I created a console application that calls the service:

try
{
    using(FaultsServiceClient faultsServiceClient = new FaultsServiceClient())
    {
        String result = faultsServiceClient.CalculateSomeStuff();
        Console.WriteLine("Result: {0}", result);
    }
}
catch(FaultException<InvalidOperationException> ex)
{
    Console.WriteLine("------------------------------");
    Console.WriteLine("FaultException of type InvalidOperationException caught.");
    Console.WriteLine("------------------------------");
    Console.WriteLine(ex.ToString());
    Console.WriteLine("------------------------------");
}
catch(Exception ex)
{
    Console.WriteLine("------------------------------");
    Console.WriteLine("Exception caught of type: {0}.", ex.GetType().Name);
    Console.WriteLine("------------------------------");
    Console.WriteLine(ex.ToString());
    Console.WriteLine("------------------------------");
}

I expected that the code inside the first catch handler, for FaultException , would be executed. Instead the second catch handler, for Exception, caught an exception of type
CommunicationObjectFaultedException. I couldn't figure out what was happening, so I did a search on the MSDN forums. The first post I found was this one. Somewhere in the middle there is a reply from Madhu Ponduru where he states the following:

using() should only be used for non-production applications (POC, etc). Production apps should use the try {…Close();} catch (CommunicationException) {Abort();} catch (TimeoutException) {Abort();} paradigm that is being used in the latest SDK samples.

He says that the Abort method should be called instead of the Close method when the proxy is in a faulted state. Bye, bye using statement. That made me feel a bit frustrated. If you read a book on WCF (I've read the excellent Programming WCF Services from cover to cover), you can't help noticing the use of a using statement in order to ensure that an instance of a proxy class gets cleaned up properly. Also, the following can be found on page 207 of Programming WCF Services:

By default, all service-thrown exceptions fault the channel so that even if the client catches that exception, it cannot issue subsequent calls because those yield a CommunicationObjectFaultedException. The client can only close the proxy.

It clearly states that it is possible to close the proxy after it went into the fault state. Searching through the MSDN library, I found the following in the documentation for the CommunicationState enumeration:

An object in the Faulted state is not closed and may be holding resources. The Abort method should be used to close an object that has faulted. If Close is called on an object in the Faulted state, a CommunicationObject-FaultedException is thrown because the object cannot be gracefully closed.

When I looked at the Dispose method of the ClientBase class in Reflector, I found out that it simply calls the Close method. Because this implies that the Dispose method can throw an exception, it means that proxy classes should not be instantiated inside a using statement. I found the following in FWDG regarding exceptions thrown from the Dispose method of the IDisposable interface:

Avoid throwing an exception from within Dispose(bool) except under critical situations where the containing process has been corrupted. Users expect that a call to Dispose would not raise an  exception.

Is closing a WCF client proxy a critical situation where the containing process has been corrupted? Get some dog food over here ;-). Some further Googling on this matter delivered this post on the MSDN forums that explains a lot. I'm not going to put the whole explanation in here, but you should definitely give it read in order to understand why they shipped it as is. Erwyn van der Meer also gives a great explanation and provides a solution to this problem in this great post. Kudos!

I strongly believe that the WCF team did a great job on the first version of the Windows Communcation Foundation. Regarding this matter, I think they made two mistakes. First, they should have communicated this a little bit better and second I think it would be best that they just got rid of the IDisposable interface for the ClientBase class.

Oh well, too late for that now.

If you and your team want to learn more about how to write maintainable unit tests and get the most out of TDD practices, make sure to have look at our trainings and workshops or check out the books section. Feel free to reach out at infonull@nullprincipal-itnull.be.

Profile picture of Jan Van Ryswyck

Jan Van Ryswyck

Thank you for visiting my blog. I’m a professional software developer since Y2K. A blogger since Y2K+5. Provider of training and coaching in XP practices. Curator of the Awesome Talks list. Past organizer of the European Virtual ALT.NET meetings. Thinking and learning about all kinds of technologies since forever.

Comments

About

Thank you for visiting my website. I’m a professional software developer since Y2K. A blogger since Y2K+5. Author of Writing Maintainable Unit Tests. Provider of training and coaching in XP practices. Curator of the Awesome Talks list. Thinking and learning about all kinds of technologies since forever.

Contact information

(+32) 496 38 00 82

infonull@nullprincipal-itnull.be