A Generic, IDisposable WCF Service Client
- by Steve Wilkes
WCF clients need to be cleaned up properly, but as they're usually auto-generated they don't implement IDisposable. I've been doing a fair bit of WCF work recently, so I wrote a generic WCF client wrapper which effectively gives me a disposable service client.
The ServiceClientWrapper is constructed using a WebServiceConfig instance, which contains a Binding, an EndPointAddress, and whether the client should ignore SSL certificate errors - pretty useful during testing! The Binding can be created based on configuration data or entirely programmatically - that's not the client's concern.
Here's the service client code:
using System;
using System.Net;
using System.Net.Security;
using System.ServiceModel;
public class ServiceClientWrapper<TService, TChannel> : IDisposable
    where TService : ClientBase<TChannel>
    where TChannel : class
{
    private readonly WebServiceConfig _config;
    private TService _serviceClient;
    public ServiceClientWrapper(WebServiceConfig config)
    {
        this._config = config;
    }
    public TService CreateServiceClient()
    {
        this.DisposeExistingServiceClientIfRequired();
        if (this._config.IgnoreSslErrors)
        {
            ServicePointManager.ServerCertificateValidationCallback =
                (obj, certificate, chain, errors) => true;
        }
        else
        {
            ServicePointManager.ServerCertificateValidationCallback =
                (obj, certificate, chain, errors) => errors == SslPolicyErrors.None;
        }
        this._serviceClient = (TService)Activator.CreateInstance(
            typeof(TService),
            this._config.Binding,
            this._config.Endpoint);
        if (this._config.ClientCertificate != null)
        {
            this._serviceClient.ClientCredentials.ClientCertificate.Certificate =
                this._config.ClientCertificate;
        }
        return this._serviceClient;
    }
    public void Dispose()
    {
        this.DisposeExistingServiceClientIfRequired();
    }
    private void DisposeExistingServiceClientIfRequired()
    {
        if (this._serviceClient != null)
        {
            try
            {
                if (this._serviceClient.State == CommunicationState.Faulted)
                {
                    this._serviceClient.Abort();
                }
                else
                {
                    this._serviceClient.Close();
                }
            }
            catch
            {
                this._serviceClient.Abort();
            }
            this._serviceClient = null;
        }
    }
}
A client for a particular service can then be created something like this:
public class ManagementServiceClientWrapper :
    ServiceClientWrapper<ManagementServiceClient, IManagementService>
{
    public ManagementServiceClientWrapper(WebServiceConfig config)
        : base(config)
    {
    }
}
...where ManagementServiceClient is the auto-generated client class, and the IManagementService is the auto-generated WCF channel class - and used like this:
using(var serviceClientWrapper = new ManagementServiceClientWrapper(config))
{
    serviceClientWrapper.CreateServiceClient().CallService();
}
The underlying WCF client created by the CreateServiceClient() will be disposed after the using, and hey presto - a disposable WCF service client.