I’ve done better! An improved service client wrapper is described here.
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<TClient, IService> : IDisposable
where TClient : ClientBase<IService>
where IService : class
{
private readonly WebServiceConfig _config;
private TClient _serviceClient;
public ServiceClientWrapper(WebServiceConfig config)
{
_config = config;
}
public TClient CreateServiceClient()
{
DisposeExistingServiceClientIfRequired();
if (_config.IgnoreSslErrors)
{
ServicePointManager.ServerCertificateValidationCallback =
(obj, certificate, chain, errors) => true;
}
else
{
ServicePointManager.ServerCertificateValidationCallback =
(obj, certificate, chain, errors) =>
errors == SslPolicyErrors.None;
}
// Or you can use:
// _serviceClient = (TClient)typeof(TClient).GetInstance(
// _config.Binding,
// _config.Endpoint);
_serviceClient = (TClient)Activator.CreateInstance(
typeof(TClient),
_config.Binding,
_config.Endpoint);
if (_config.ClientCertificate != null)
{
_serviceClient.ClientCredentials.ClientCertificate
.Certificate = _config.ClientCertificate;
}
return _serviceClient;
}
public void Dispose()
{
DisposeExistingServiceClientIfRequired();
}
private void DisposeExistingServiceClientIfRequired()
{
if (_serviceClient != null)
{
try
{
if (_serviceClient.State == CommunicationState.Faulted)
{
_serviceClient.Abort();
}
else
{
_serviceClient.Close();
}
}
catch
{
_serviceClient.Abort();
}
_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)
{
}
}
…or with an alias in the using list (if you don’t need a reusable class):
using ManagementServiceClientWrapper =
ServiceClientWrapper<ManagementServiceClient, IManagementService>;
…where ManagementServiceClient
is the auto-generated client class, and the IManagementService
is the auto-generated WCF service interface - and used like this:
using (var wrapper = new ManagementServiceClientWrapper(config))
{
wrapper.CreateServiceClient().CallService();
}
The underlying WCF client created by the CreateServiceClient()
call will be disposed after the
using()
, and hey presto - a disposable WCF service client.
Edit: I’ve added an example application using the client at https://bitbucket.org/MrSteve/wcfserviceclientexample.
Comments
4 comments