DevTrends

How not to do dependency injection - the static or singleton container

Dependency injection and the use of IoC containers is becoming more and more popular but many development teams do not have the knowledge or experience necessary to fully utilise the power of the IoC container. In the next few posts, we will take a look at the most common mistakes and how to address them. In this post, we are going to talk about the static or singleton container and why this 'pattern' is such a bad idea.

This is part one of a three part series on dependency injection mistakes. All the articles in the series are listed below:

Dependency Injection and the IoC container

Before we begin, let's get something out of the way:

Dependency Injection != Using an IoC container

It is this second point that we are going to talk about in this article. In my experience, by far the most common IoC mistake is to wrap up the container in a public static or singleton class that is referenced throughout the code base. It is important to realise that this is not dependency injection, it is service location which is widely regarded as an anti-pattern. I cannot over-emphasise how important it is to move away from this design and to inject your dependencies from the root of your application. In fact, virtually all other IoC mistakes come about as a direct result of this misunderstanding.

The problem

Let's start from the beginning and very briefly look at life without DI. It is often easy to visualise problems by way of an example, so let us consider the following common architecture:

ASP.NET MVC Controller -> Service Layer -> Repository -> Entity Framework DB Context

If we begin by just looking at a very basic controller that needs to interact with a service layer. Without dependency injection, you would most likely instantiate the service in the controller's constructor, or in each method that the service is being used in.

public class HomeController
{
  private readonly IExampleService _service;

  public HomeController()
  {
    _service = new ExampleService();
  }

  public ActionResult Index()
  {
    return View(_service.GetSomething());
  }
}

So we know that this is bad. Our controller is tightly coupled to the ExampleService and as a result, there is no way to unit test the controller. So how do we address these shortcomings? If you were to search the web for a solution then sooner or later, you would find articles that talk about dependency injection and the use of IoC Containers. Unfortunately, much of what you read on the web about IoC is wrong, so depending on what you read, your design choices may end up being far from ideal.

How to use the IoC container badly - no dependency injection

We can all agree that we really need to remove the fixed dependency on ExampleService from the controller but how we go about this is not so clear. People often seem to completely forget that we are trying to inject dependencies and instead, use the container to retrieve them. Instead of the controller being supplied with the service dependency, they leave it up to the controller to request it.

public class HomeController
{
  private readonly IExampleService _service;

  public HomeController()
  {
    _service = Container.Instance.Resolve<IExampleService>();
  }

  public ActionResult Index()
  {
    return View(_service.GetSomething());
  }
}

This is the birth of the static container. Instead of changing the constructor of the controller to take in the dependency, we are just changing the line where the service is instantiated to resolve it using the the container instead. Most (all?) containers themselves are not static but you will find many examples on the web showing how to wrap the container up in a static class or as a singleton. With this done, you can simply call the container from anywhere in your codebase. Congratulations, you are now using an IoC container very badly and without dependency injection.

Whilst it can be argued that this approach does reduce coupling between the controller and service and also allows the controller to be unit tested, what we are doing is not dependency injection. Nothing is being injected into the controller - the parameterless constructor gives that away. Instead we are using the container in a way that we want to avoid within our code - as a service locator. So why is this so bad?

Firstly, every class which uses the container in this way has a direct dependency on it, so we are effectively removing one coupling and adding another. Some people might argue that this approach allows you to replace multiple hard-coded dependencies with a single container dependency, effectively reducing coupling but this is missing the point. An IoC container should be there to assist in the building of dependency graphs and as we said previously, you should be able to remove the container and build your graph manually without requiring any changes to the code (other than the root class that starts the application). Using the container as a service locator couldn't be further from this ideal. Without the container, your code will not run at all and any component with a dependency must reference the container.

The other major issue is the fact that it is very unclear what is going on. The beauty of dependency injection is that just by looking at the constructor of a class, you can tell exactly what it depends upon. You then provide these dependencies. If you are unit testing the class, you can manually inject stubs or mocks very simply. Importantly, in your unit test project, you do not need to reference the container at all. The static container approach is the opposite. The caller does not supply anthing. Rather, the component goes off and gets what it needs using the container as a service locator. The constructor will typically be empty and without looking thoroughly at the code, it is difficult to determine any dependencies. To unit test a class built in this way, you need to use the container in your unit tests and must configure the container to return fakes for dependencies. Not only is any configuration in unit tests a big red flag indicating that something is not quite right, it also makes it very difficult to use a mocking framework. Modern mocking frameworks such as Moq and RhinoMocks can dramatically improve unit test productivity, but when using the static container, you will most likely end up writing your mocks manually which can be pretty tedious in larger applications.

How to use the IoC container correctly - dependency injection

Although the title of this section states 'How to use the IoC container correctly', if you look at the code below, you will not find a reference to the container at all. This is exactly what we want. 99% of your code base should have no knowledge of your IoC container. It is only the root class or bootstrapper that uses the container and even then, a single resolve call is all that is typically necessary to build your dependency graph and start the application or request.

The code below is very readable and easy to understand. Just a brief look at the constructor tells us that the controller requires an implementation of IExampleService in order to function. If we should want to instantiate the class ourselves, it would be trivial to do so, passing in the constructor dependency. For unit testing, we can inject a mock service and test the interaction between the components. All very simple. No configuration or knowledge of the container necessary. This is dependency injection.

public class HomeController
{
  private readonly IExampleService _service;

  public HomeController(IExampleService service)
  {
    _service = service;
  }

  public ActionResult Index()
  {
    return View(_service.GetSomething());
  }
}

But what about the container? As we have mentioned previously, the important thing about using the container is that you should only interact with it at the entry point of the application. You register all your components with the container and then resolve the root component using the container. All dependencies are satisfied for the root component and all child components - the entire dependency graph. This is all there is to it for a console application, but for website or WCF services, it is a little more complicated. Firstly, whilst we still need to register all the components once at application startup, when resolving, we typically want to resolve once per request. The complication is finding the right place to do the resolve. Fortunately, both WCF and MVC have well-defined points available to hook into the pipeline and packages are readily available to assist with this integration. For MVC3 and Unity integration, you can use the Unity.Mvc3 NuGet Package to get up to speed very quickly.

Any other concerns?

Abstracting the container

People often talk about the need to abstract out the IoC container so you are not directly dependent on one particular product. Whilst in general this philosphy may be a good idea, in the case of an IoC container used correctly, it is unnecessary and unproductive. This is because the IoC container should only be used in a single class at the root of your application. If you want to change your container, you simply change that class - abstractions are totally unnecessary and in fact can often do more harm than good. When you create an abstraction, you will inevitably reduce the functionality available. IoC containers differ quite significantly in functionality, so trying to abstract an interface that will work with multiple containers will mean than features unique to one container cannot be in the interface. It is only if you are mis-using the container that the requirement to abstract it has any validity.

Dynamic component resolution

Another reason cited is the need to resolve components dynamically. It is a common requirement to be able to create an object based on data that can only be know at run-time. A slight variation of this is that if you have a component that is expensive to create, so you may want to delay the instatiation of this object until/if it is required. Both of these scenarios can be easily handled without resorting to accessing the container deep within your code. The answer is factories. Most IoC containers have support for factories and Unity is no exception.

If you need runtime data in order to instantiate a component, you can create a custom factory. When registering the components with Unity, you also register a factory. Looking at the registration code below, the numerous lambda's make the code quite hard to understand, but all we are doing is registering a delegate that takes in a string and returns an IExampleService. You can have any kind of logic you want in this delegate, but for this example, we are just using the string to resolve a named instance of IExampleService. We have therefore registered another IExampleService implementation with the container and named both registrations.

private static IUnityContainer BuildUnityContainer()
{
    var container = new UnityContainer();

    container.RegisterType<IExampleService, ExampleService>("default");
    container.RegisterType<IExampleService, AnotherExampleService>("another");

    container.RegisterType<Func<string, IExampleService>>(
        new InjectionFactory(c => 
        new Func<string, IExampleService>(name => c.Resolve<IExampleService>(name))));

    container.RegisterControllers();

    return container;
}

The controller code does not change dramatically and most importantly, we do not have a reference to the IoC container. We are only using built-in .NET constructs. The constructor changes to take in the delegate that we registered in the previous code snippet. We are hard-coding the service implementation string in this example, but it would typically come from another component which would get the data dynamically. We then call the delegate factory with this string and assign the resultant IExampleService implementation to the private member variable which is then used throughout the controller.

public class HomeController
{
  private IExampleService _service;

  public HomeController(Func<string, IExampleService> serviceFactory)
  {
    var exampleServiceImplementation = "default"; // TODO get dynamically
    _service = serviceFactory(exampleServiceImplementation);
  }

  public ActionResult Index()
  {
    return View(_service.GetSomething());
  }         
}

If you want to lazy load a component, you can take advantage of Unity's automatic factory support. Just register your component in the usual way, but change any class that depends on the component, to take in a Func rather than a T. There is no need to register the factory with Unity if it is a simple Func and does not require additional data.

public class HomeController
{
  private IExampleService _service;
  private readonly Func<IExampleService> _serviceFactory;

  public HomeController(Func<IExampleService> serviceFactory)
  {
    _serviceFactory = serviceFactory;
  }

  public ActionResult Index()
  {
    return View(Service.GetSomething());
  }

  private IExampleService Service
  {
    get { return _service ?? (_service = _serviceFactory()); }
  }
}
Some IoC containers such as AutoFac support the newer Lazy class introduced with .NET 4 which can be used in place of the Func delegate, but unfortunately, right now, out of the box, Unity does not support Lazy.

Conclusion

Depedency injection and using an IoC container are not the same thing and either one can be done without the other. Using an IoC container statically, as a service locator throughout the code base is a common anti-pattern and this post has tried to explain why it should be avoided. Proper dependency injection does not rely on a container and no component should know anything about the container. Instead dependent components are simply passed (injected) via the constructor and at the root of the application, we can either build the depedenncy graph manually or use the container to resolve the dependency graph automatically. Even if you need lazy loading capabilities or have components that need runtime data to be instantiated, you can still do proper dependency injection without resorting to the evil static or singleton container.