Wednesday, December 11, 2013

How to correctly dispose CoreService client objects

Today I was doing some research in the WCF internals and I realized that the stories around the “using” statement are not all true. If you are a C# developer you are familiar with the “using” statement and you know that it will save lines of code since it will explicitly call the Dispose method in the object getting instantiated in the “using” statement (the object must implement the IDisposable interface).

The sentence above is not true for WCF clients like the CoreServiceClient or SessionAwareCoreServiceClient classes because they are typed WCF clients.

Why I cannot use “using” to safely dispose CoreService clients?

The answer is pretty simple the Dispose method calls the Close method and it might throw an exception if a Transport related exception happens. So it is not correct to use “using” because you are not managing exceptions correctly and eventually the underline communication object will remain undisposed.

Sample:

using (channel = new CoreServiceClient("basicHttp_2013")) {
    ComponentData component = (ComponentData)channel.Read("tcm:5-2051", new ReadOptions());
} // Dispose will be called here and an exception might happen.

// This code might not be reached
Console.WriteLine("I have sucessfully retrieved my component");


I know I have some samples where I was using “using” and having a try catch finally block in order to handle exceptions and try to close the channel, it might help but there are still some gaps.
Sample:

using (channel = new CoreServiceClient("basicHttp_2013")) {
    try {
        ComponentData component = (ComponentData)channel.Read("tcm:5-2051", new ReadOptions());
    }
    catch (Exception ex) { // This code will manage any exception that might happen in the try block       
 throw ex;
    }
    finally {
        if (channel.State != CommunicationState.Closed) {
            channel.Close(); // This code might throw an exception if there is a Network issue
        }
    }
               
} // Dispose will be called here and an exception might happen if there is a Network issue.

// This code might not be reached
Console.WriteLine("I have sucessfully retrieved my component");


What is the right way to Dispose a CoreService client object?

Microsoft recommends a way to do it, basically they don’t use the “using” statement and they use a classic way to manage exceptions as back in the .Net Framework 1.1 J

Solution:

CoreServiceClient channel = new CoreServiceClient("basicHttp_2013");
try {
    ComponentData component = (ComponentData)channel.Read("tcm:5-2051", new ReadOptions());

    channel.Close(); //This line might throw a network exception
               
    Console.WriteLine("I have sucessfully retrieved my component");
}
catch (CommunicationException ex) {
    channel.Abort(); //The channel is aborted and the resources released.
}
catch (TimeoutException ex) {
    channel.Abort(); //The channel is aborted and the resources released.
}
catch (Exception ex) {
    channel.Abort(); // The channel is aborted and the resources released.
}


I know it looks tedious but we can put it in an Extension method or a Utility so that we don’t have to write all these catch sentences all the time.

No comments:

Post a Comment