Use Common Instance Factory to Abstract Away the Dependency Injection Container
Download the Common Instance Factory with WCF Extensions here and is also available on NuGet.
A while back I wrote a blog post on the Onion Architecture, an approach to building loosely-coupled applications where you can swap out particular components without affecting the rest of the application. They key to making it all work is the use of Dependency Injection, also known as Inversion of Control, to delegate creation of types to an external container. There are various ways to implement dependency injection, but the most common is a technique called “constructor injection,” in which a class provides a constructor that accepts one or more interfaces as parameters. Concrete implementations of each interface are registered with the DI container and supplied to the constructor when a request for the type is made from the container.
public class GreetingService : IGreetingService
{
private readonly IGreetingRepository _greetingRepository;
public GreetingService(IGreetingRepository greetingRepository)
{
_greetingRepository = greetingRepository;
}
public string Greet(string name)
{
string greeting = _greetingRepository.GetGreeting();
return string.Format('{0} {1}', greeting, name);
}
}
In this example, an IGreetingRepository is passed to the GreetingService’s constructor. GreetingService doesn’t care how IGreetingRepository is implemented. It’s the job of the DI container to provide whichever implementation of IGreetingRepository was registered with the container. This promises the architect’s nirvana of loose coupling, because the GreetingService is abstracted away from the implementation of IGreetingRepository, which allows you to switch from one persistence stack to another without affecting parts of the application which depend on it.
Ah, but there’s a problem. You have to select a DI container from one of numerous proprietary and open-source products on the market and then marry yourself to it. You are then tightly coupled to the DI container! Now, there are some best practices when it comes to using a DI container, which make it less traumatic to switch from one to another, such as registering dependencies at the composition root, or entry point, of the application. Still, placing a layer of abstraction between your application and the DI container allows for greater flexibility, which is what loose-coupling is all about.
Until recently, I was content to select a DI container, based on its features and ease-of-use, and learn to live with it. Then I started looking at performance benchmarks for various DI containers. It turnes out my favorite container, Ninject, was one of the worst performing. So it was time to look at switching to another container for the application I was writing. This didn’t mean, however, I had to jettison Ninject altogether. A lot of DI-specific code is needed for unit tests, where there is extensive mocking, and advanced features of a DI container such as Ninject come in handy.
When searching for a way to abstract away the DI container, the first solution I examined was the Common Service Locator, built by Microsoft’s Patterns and Practices group back in 2008 with the source code posted on CodePlex. However, I found a couple of deficiencies. First, and most egregious, is that it is modeled as a service locator, rather than an abstract factory. In his article, Inversion of Control Containers and the Dependency Injection Pattern, Martin Fowler describes some of the weaknesses of the service locator anti-pattern. He states, “With a Service Locator every user of a service has a dependency to the locator,” and that “the locator can hide dependencies to other implementations.”
The problem arises when a class directly references the locator, using it to instantiate types it depends on, which creates a dependency on the locator and hides the actual dependencies of the class. While it is possible to use the Common Service Locator without falling into this trap, the base interface, IServiceLocator, is a non-generic interface with a generic method that allows you to create an infinite number of types, making it easier for classes to use it directly.
This was undoubtedly a design-decision by the MS team to achieve a wider adoption by making the Common Service Locator compatible with both dependency injection and service location frameworks. However, a cleaner alternative is the abstract factory pattern, which can be expressed as a generic interface with a method that only return instances of a single type. This discourages folks from using the factory for service location and instead promotes the dependency injection pattern described by Martin Fowler.
Another weakness of Common Service Locator is that it does not provide a ReleaseInstance method. Some containers manage the lifetime of instances internally and there needs to be a way to ask a container to release an instance under its control.
This led me to develop the Common Instance Factory, as an alternative to the Common Service Locator, and to extend it with support for WCF services that are decoupled from any particular DI container. Notice it’s a “factory” versus “locator” and that it produces “instances” instead of “services” (while technically more accurate, I found the term “service” to be overused and sometimes misleading). Here is the root interface used for resolving instances.
public interface ICommonInstanceFactory<TInstance>
{
TInstance GetInstance();
IEnumerable<TInstance> GetAllInstances();
void ReleaseInstance(TInstance instance);
}
The base implementation is an abstract class with methods which container-specific adapters need to override.
public abstract class CommonInstanceFactoryBase<TInstance> : ICommonInstanceFactory<TInstance>
where TInstance : class
{
public TInstance GetInstance()
{
return InternalGetInstance();
}
public IEnumerable<TInstance> GetAllInstances()
{
return InternalGetAllInstances();
}
public void ReleaseInstance(TInstance instance)
{
InternalReleaseInstance(instance);
}
protected abstract TInstance InternalGetInstance();
protected abstract IEnumerable<TInstance> InternalGetAllInstances();
protected abstract void InternalReleaseInstance(TInstance instance);
}
To start with, I’ve written two adapters, one for Ninject (slow but with a lot of features) and one for SimpleInjector (fast but with fewer features). The implementation of the abstract base class is quite straightforward, so there’s not much effort required to write adapters for other DI containers. (Stay tuned for more!) Here’s the Ninject adapter.
public class NinjectInstanceFactory<TInstance> : CommonInstanceFactoryBase<TInstance>
where TInstance : class
{
private readonly IKernel _container;
public NinjectInstanceFactory(IKernel container)
{
_container = container;
}
protected override TInstance InternalGetInstance()
{
var instance = _container.Get<TInstance>();
return instance;
}
protected override IEnumerable<TInstance> InternalGetAllInstances()
{
var instances = _container.GetAll<TInstance>();
return instances;
}
protected override void InternalReleaseInstance(TInstance instance)
{
_container.Release(instance);
}
}
To use it all you have to do is new up the NinjectInstanceFactory, supplying an initialized container to the constructor. Here is a unit test that demonstrates the usage.
[TestFixture]
public class NinjectAdapterTests
{
private IKernel _container;
[TestFixtureSetUp]
public void TestSetup()
{
_container = new StandardKernel();
_container.Load<GreetingModule>();
}
[Test]
public void Ninject_Adapter_Should_Get_GreetingService()
{
// Arrange
var resolver = new NinjectInstanceFactory<GreetingService>(_container);
// Act
var greeter = resolver.GetInstance();
string greeting = greeter.Greet('Tony');
// Assert
Assert.That(greeting, Is.StringMatching('Howdy Tony'));
}
}
So far, this really isn’t that big of a deal. The client still needs to initialize the container and pass it to the instance factory. So what’s the advantage? The power of the abstraction comes to the fore when using dependency injection with frameworks such as ASP.NET MVC or WCF. Particularly with WCF, where you need other pieces (such as an instance provider, service behavior and service host), the abstraction afforded by the Common Instance Factory provides a uniform way to deal with different DI containers so that swapping out one for another is much easier. That will be the topic of my next blog post.
Download the Common Instance Factory from NuGet, or get the source code and samples from the CodePlex site.
Reference: Use Common Instance Factory to Abstract Away the Dependency Injection Container from our NGC partner Tony Sneed at the Tony Sneed’s Blog blog.