Saturday 25 August 2012

Do not use "using" for WCF Clients

Conventionally using() block disposes WCF clients wrongly when there's a communication exception, eg disconnecting network connection. It lift exception during the dispose and thus the resources held by the WCF client aren't released properly. This will result into memory leaks.
 C# and Wcf Performance
As we know that any IDisposable object must be disposed using “using” keyword. So, you have been using “using” to wrap WCF service’s ConnectionFactory and Clients like this:
using(var client = new ConClient()) {
.
.
.
}

Or, if you are doing it the hard and slow way (without really knowing why), then:
using(var factory = new ConFactory<IConService>()) {
var con= factory.CreateCon();
.
.
.
}

That’s what we have learnt while working in .Net? its not fully right?
When there’s a network related error or the connection is disconnected, or the service is expired before Dispose is called by the using keyword, then it results in the following exception when the using keyword tries to dispose the con;
failed: System.ServiceModel.CommunicationObjectFaultedException :
The communication object, System.ServiceModel.Cons.ServiceCon,
cannot be used for communication because it is in the Faulted state.
   
    Server stack trace:
    at System.ServiceModel.Cons.CommunicationObject.Close(TimeSpan timeout)
   
    Exception rethrown at [0]:
    at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
    at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
    at System.ServiceModel.ICommunicationObject.Close(TimeSpan timeout)
    at System.ServiceModel.ClientBase`1.System.ServiceModel.ICommunicationObject.Close(TimeSpan timeout)
    at System.ServiceModel.ClientBase`1.Close()
    at System.ServiceModel.ClientBase`1.System.IDisposable.Dispose()

There are various causes for which the fundamental connection can be at disconnected before the using block is finished and the .Dispose() is raised. Common problems like network connection disconnection. Do NOT use using on WCF Con/Client/ConFactory. Instead you need to use an alternative. First create an extension method.
public static class WcfMyExtensions
{
    public static void Using<T>(this T myclient, Action<T> work)
        where T : ICommunicationObject
    {
        try
        {
            work(myclient);
            myclient.Close();
        }
        catch (CommunicationException e)
        {
            myclient.Abort();
        }
        catch (TimeoutException e)
        {
            myclient.Abort();
        }
        catch (Exception e)
        {
            myclient.Abort();
            throw;
        }
    }
}

Then use this instead of the “using” keyword:
new ConClient().Using(con => {
    con.Login(username, password);
});

Or if you are using ConFactory then:

new ConFactory<IConService>().Using(con => {   
    con.Login(username, password);
});

No comments :