The most intuitive way of handling a generated WCF client’s life cycle is by putting it into a using
block:
using (var svc = new MyServiceClient())
{
var result = await svc.SumAsync(1, 2);
}
Note: You should not use static or singleton client objects.
However, the problem with this code is, that IDisposable
is not implemented correctly in the base class ClientBaseDispose
method always calls Close
but Close
may throw an exception. If this exception is thrown an additional call to Abort
is needed but which is not made. Missing this Abort
call may leave the client object in a faulted state and subsequent instances may be corrupted. You can find more details on this MSDN page; however, the presented solution is wrong which is discussed in this StackOverflow question.
To fix the dispose mechanism of the client instance, you have to “extend” the class using a partial implementation. This way you can override the IDisposable
implementation and fix the original implementation. Just create a partial class for each generated WCF service client:
public partial class MyServiceClient : IDisposable
{
private bool _isDisposed;
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. </summary>
public void Dispose()
{
ServiceClientUtilities.Dispose(this, ref _isDisposed);
}
/// <summary>Finalizer. </summary>
~MyServiceClient()
{
Dispose();
}
}
After extending the generated class with this code, you can safely use the code shown at the beginning of the article. The following class contains the reusable Dispose
implementation:
/// <summary>Provides utility methods for WCF service clients. </summary>
public static class ServiceClientUtilities
{
/// <summary>Disposes the service client. </summary>
/// <param name="service">The service client. </param>
/// <param name="isDisposed">The reference to a value indicating whether the service is disposed. </param>
public static void Dispose(ICommunicationObject service, ref bool isDisposed)
{
if (isDisposed)
return;
try
{
if (service.State == CommunicationState.Faulted)
service.Abort();
else
{
try
{
service.Close();
}
catch (Exception closeException)
{
try
{
service.Abort();
}
catch (Exception abortException)
{
throw new AggregateException(closeException, abortException);
}
throw;
}
}
}
finally
{
isDisposed = true;
}
}
}
The shown utilities class can be downloaded here:
- ServiceClientUtilities.cs, included in the MyToolkit project
A complete sample solution can be downloaded from this GitHub repository.
Rico Suter
SOFTWARE ENGINEERING
EDIT
.NET C# Client Proxy WCF