You most likely wouldn't want to inject a WCF client because you only need it for a very short time. What you can inject is a factory that will return the service when needed.
The factory interface may look like this:
public interface IMyServiceFactory
{
IMyService Create();
void Release(IMyService created);
}
Assume that you're injecting this through your constructor and adding a private readonly field to your class, like this:
private readonly IMyServiceFactory _myServiceFactory;
Then when you need the service, you do this:
var myService = _myServiceFactory.Create();
try
{
// do something with the service
}
finally
{
_myService.Release(myService);
}
A big benefit is that your class depends entirely on abstractions. It doesn't "know" that the service is implemented by a WCF client or that the factory is calling a DI container. You can test it using a mock of IMyService
. That's impossible if your class is directly creating its own WCF client.
You didn't mention which container you're using, but many of them will create WCF clients for you to implement interfaces.
- Autofac
- Windsor - their documentation is lacking at this point. In the off chance that you're using Windsor I can provide more detail.
Another nice detail about Windsor is that it will also create the abstract factory for you.
Here's a few more pieces to make up a sample implementation using Windsor. This supposes that you have a WCF service that implements IMyService
.
Here's the service interface, the factory interface, and the class that consumes it:
public interface IMyService
{
IEnumerable<string> GetSomeData();
}
public interface IMyServiceFactory
{
IMyService Create();
void Release(IMyService created);
}
public class ClassThatConsumesService
{
private readonly IMyServiceFactory _serviceFactory;
public ClassThatConsumesService(IMyServiceFactory myServiceFactory)
{
_serviceFactory = myServiceFactory;
}
public void MethodThatDoesSomething()
{
var service = _serviceFactory.Create();
try
{
var data = service.GetSomeData();
// do whatever
}
finally
{
_serviceFactory.Release(service);
}
}
}
Then here's an example of some implementation details using Windsor. But one important detail is that nothing above depends on Windsor. You could do this using a different DI container. You don't even need a DI container at all. All your class knows is that it's calling a factory to get an instance of a service.
public class ClassThatConsumesService
{
private readonly IMyServiceFactory _serviceFactory;
public ClassThatConsumesService(IMyServiceFactory myServiceFactory)
{
_serviceFactory = myServiceFactory;
}
public void MethodThatDoesSomething()
{
var service = _serviceFactory.Create();
try
{
var data = service.GetSomeData();
// do whatever
}
finally
{
_serviceFactory.Release(service);
}
}
}
To use Windsor you would add the Windsor WCF Facility nuget package, which is Windsor plus some additional classes for handling WCF services.
Your container registration might look like this:
container.AddFacility<TypedFactoryFacility>();
container.AddFacility<WcfFacility>();
container.Register(Component.For<IMyService>()
.AsWcfClient(WcfEndpoint.FromConfiguration("MyServiceEndpointName")));
container.Register(Component.For<IMyServiceFactory>().AsFactory());
This does the following:
- Adds the "facility" or capability for the container to provide an abstract factory (I'll come back to that.)
- Adds the WCF facility for managing WCF services
- Tells the container that the implementation of
IMyService
is a WCF client using the endpoint specified in app.config/web.config named "MyServiceEndpointName".
- Tells the container that the implementation of
IMyServiceFactory
is a factory that Windsor creates. Here's that documentation again.. What that means is that you don't actually create a class to implement IMyServiceFactory
. The container does it. When you call Create
the factory creates the client. When you call Release
it disposes the client.
If you wanted to you could write your own factory implementation, like this:
public class WcfClientMyServiceFactory : IMyServiceFactory
{
public IMyService Create()
{
return new MyServiceClient();
}
public void Release(IMyService created)
{
var client = (MyServiceClient) created;
try
{
try
{
client.Close();
}
catch
{
client.Abort();
}
}
finally
{
client.Dispose();
}
}
}
(Don't quote me on the details of how to properly close a WCF client. It's been a while and I'm rusty.)
But having gotten used to using Windsor it's just a lot easier.
Having done it this way, what if you want to unit test your class assuming that IMyService
will return specific data? Now it's really easy to use Moq or just write test double classes like this:
public class MyServiceDouble : IMyService
{
public IEnumerable<string> GetSomeData()
{
return new [] {"x", "y", "z"};
}
}
public class MyServiceFactoryDouble : IMyServiceFactory
{
public IMyService Create()
{
return new MyServiceDouble();
}
public void Release(IMyService created)
{
// Nothing to clean up.
}
}
Because your class doesn't know anything about IMyService
- it doesn't know that the "normal" implementation is a WCF client - it's easy to replace it with something else.