Select Page

Dependency Injection has become quite the buzz word over the past years, and even though it might seem like a daunting and complex topic to grasp at first, it is actually a lot easier than you would think. You may have even already applied or come across it in your own code without realizing that you were using some form of dependency injection.

In fact, if you’re a .NET developer then you have probably used the Stream class and passed instances of it either to a function or the constructor of a class at some point:

void WriteHelloWorld(Stream targetStream)
{
    using (TextWriter writer = new StreamWriter(targetStream))
    {
        writer.WriteLine("Hello World");
    }                
}

Believe it or not, but this is the basis of dependency injection. After all, the WriteHelloWorld method depends on the Stream class in order to do its work and so does the StreamWriter class. By passing (or injecting) a Stream object into the method and into the StreamWriter constructor, instead of having them create it themselves, we enable the use of polymorphism to easily swap out the behavior of the WriteHelloWorld method. When we pass it a FileStream object its data will be written to a file but if we provide it with a MemoryStream object instead, then the data will be written to memory.

Of course since it is an architectural design pattern there are some additional software design principles and patterns we should follow in order to get the most out of Dependency Injection, and — although not required — helpers like DI containers (or IoC containers) can make your Dependency Injection experience a lot easier.

Coupling

In his book Dependency Injection in .NET, Mark Seemann writes:

Dependency Injection is nothing more than a technique that enables loose coupling.

This means that we can’t really talk about Dependency Injection before we understand the concept of coupling and why tight coupling is bad.

Coupling describes how much a module (which could be a class or an assembly) relies or depends on another module (class/assembly) in order to do its work.

When two modules are tightly coupled, it means that they have a strong relationship. This is considered a bad thing since it can result in a ripple effect; if one module is changed then this requires the modules that depend on it to be changed as well. It also makes a module harder and often even impossible to test, since the module it depends on cannot be replaced with a dummy, or mocked version.

Imagine the follow code:

public class SqlServerDatabaseConnection
{
    // Concrete SQL Server Implementation
}

public class CustomerRepository
{
    private readonly SqlServerDatabaseConnection _databaseConnection;

    public CustomerRepository()
    {
        _databaseConnection = new SqlServerDatabaseConnection();
    }

    public Customer[] GetCustomers()
    {
        // uses _databaseConnection to retrieve customers.
    }
}

This class exhibits tight coupling. It actually has two dependencies:

  • It relies on a concrete implementation of the SqlServerDatabaseConnection class, which cannot be swapped out.
  • As a result, it also makes the application completely reliant on a specific database engine, namely SQL Server.

We cannot eliminate coupling entirely, but we can minimize the strength and the impact of the coupling. This is where Low Coupling comes in. It refers to modules that have a weak relationship and is what we should strife for as much as possible.

Returning to the code example, simply passing an instance of SqlServerDatabaseConnection into the constructor of the CustomerRepository class won’t do much to solve the tight coupling problem, since it would still depend on the concrete implementation and be bound to the SQL Server database engine.

One solution would be to use an abstract class called DatabaseConnection, inherit SqlServerDatabaseConnection from that. Then we could make the CustomerRepository depend on the abstract class instead of the concrete implementation and inject any class which inherits from DatabaseConnection into it.

public abstract class DatabaseConnection
{
    // Abstract methods for running queries etc.
}

public class SqlServerDatabaseConnection : DatabaseConnection
{
    // Concrete SQL Server Implementation
}

public class OracleDatabaseConnection : DatabaseConnection
{
    // Concrete Oracle Implementation
}

public class CustomerRepository
{
    private readonly DatabaseConnection _databaseConnection;

    public CustomerRepository(DatabaseConnection databaseConnection)
    {
        _databaseConnection = databaseConnection;
    }

    public Customer[] GetCustomers()
    {
        // uses _databaseConnection to retrieve customers.
    }
}

By programming against an abstract class instead of depending on a concrete implementation, we have successfully minimized the coupling of the CustomerRepository class. If we now want to switch to an Oracle database, we can and for testing purposes we can even pass a mocked implementation to the repository class.

CustomerRepository customerRepository = new CustomerRepository(new SqlServerDatabaseConnection());
CustomerRepository customerRepository = new CustomerRepository(new OracleDatabaseConnection());

This is a perfectly valid solution for loose coupling and is commonly applied. There is just one problem with using abstract classes and that is that they can still contain an implementation, which makes it very tempting to write virtual methods for certain functionality. Whenever that happens, we are essentially still depending on a class that has at least some concrete implementations, which once again causes coupling.

In order to avoid this problem altogether, we take this one step further and follow the advice of the Gang of Four on good object-oriented software design:

Program to an ‘interface’, not an ‘implementation’.

Because interfaces are essentially contracts which cannot contain any implementation code, it is safe to create code that depends on them.

public interface IDatabaseConnection
{
    // Definitions for running queries etc.
}

public class SqlServerDatabaseConnection : IDatabaseConnection
{
    // Concrete SQL Server Implementation
}

public class OracleDatabaseConnection : IDatabaseConnection
{
    // Concrete Oracle Implementation
}

public class CustomerRepository
{
    private readonly IDatabaseConnection _databaseConnection;

    public CustomerRepository(IDatabaseConnection databaseConnection)
    {
        _databaseConnection = databaseConnection;
    }

    public Customer[] GetCustomers()
    {
        // uses _databaseConnection to retrieve customers.
    }
}

Since abstract classes and interfaces are similar, the usage of the CustomerRepository will be exactly the same:

CustomerRepository customerRepository = new CustomerRepository(new SqlServerDatabaseConnection());
CustomerRepository customerRepository = new CustomerRepository(new OracleDatabaseConnection());

One thing to remember is that we can’t prevent coupling everywhere, and it is okay to have coupling in some places. I think Martin Fowler made a great statement on this topic:

I concern myself most with coupling at the highest-level modules. If we divide a system into a dozen (or fewer) large-scale pieces, how are these pieces coupled? I focus on the coarser-grained modules, because worrying about coupling everywhere is overwhelming.
The biggest problems come from uncontrolled coupling at the upper levels.

Martin Fowler, “Reducing Coupling” article in IEEE SOFTWARE 2001

There are also several different types of coupling than the ones I’ve described here, but for the sake of understanding dependency injection this covers all you need to know of coupling. For more detailed information on the topic of coupling, I refer you to the Wikipedia article on the subject.

Dependency Injection Patterns

There are four basic Dependency Injection patterns, or techniques:

  • Constructor Injection
  • Property Injection
  • Method Injection
  • Ambient Context

The main difference between these four patterns is the way in which the dependencies are injected. From all of these patterns, the most important, and commonly used is the Constructor Injection pattern. This pattern should be used in most situations, whereas the other patterns have very specialized use cases.

Constructor Injection

As the name implies this pattern injects the dependencies through the class’s constructor. By using the constructor the caller is forced to supply the dependency in order to be able to create an instance of the class.
This method should be your default choice for Dependency Injection since it fits the most common scenarios and has the advantage that it guarantees that the dependency is present. That guarantee is especially valuable when the depending class cannot function without the dependency.

Constructor Injection is very easy to implement. The class that needs the dependency must expose a public constructor that accepts an instance of the required dependency, or dependencies as a constructor argument. This works best if this is the only available constructor. Inside the constructor, the dependency references should then be stored for future (or immediate) use, preferably in a field marked with the readonly modifier.

Since both interfaces and abstract classes are reference types, we should also add a guard clause to our constructor to prevent the caller from passing null as an argument to make the code compile. This also bolsters the guarantee that the dependency is present.

public class CustomerRepository
{
    private readonly IDatabaseConnection _databaseConnection;

    public CustomerRepository(IDatabaseConnection databaseConnection)
    {
        if (databaseConnection == null)
        {
            throw new ArgumentNullException("databaseConnection");
        }
    
        _databaseConnection = databaseConnection;
    }
}

If you think this looks a lot like the earlier examples, then you would be right. Almost all of the previous examples in this article used the constructor injection pattern.

Property Injection

Property Injection is sometimes also called Setter Injection. It works by exposing a writable property (setter) that allows the caller to supply a dependency. Because it is easy to forget to assign a property, especially since the compiler won’t complain about it, this pattern should only be used if the class you are developing already has a good default instance of the dependency, but you still want to enable callers to replace it with a different implementation or if the dependency is optional.

There are two ways to implement the Property Injection pattern.

No Default

This is the easiest implementation, but it is also the most fragile.

public class Worker
{
    public INotificationService NotificationService { get; set; }
}

Because the property isn’t guaranteed to be set, it might be null. If the sending of notifications is optional this is fine, because then we can simply check the property for null and skip sending notifications if the dependency isn’t set.

Since there is no default, this method should really only be used if the dependency is optional.

With Default

When we have a good default, we can make the property more robust and add a simply guard clause to prevent the caller from setting the dependency to null.

public class Worker
{
    private INotificationService _notificationService;
    
    public INotificationService 
    { 
        get
        {
            if (_notificationService == null)
            {
                _notificationService = new DefaultNotificationService();
            }
            
            return _notificationService;
        }
        set
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }
            
            _notificationService = value;
        }
    }     
}

Method Injection

Method injection is useful when the dependencies can vary with each method, or if the dependency is only required for a single method in the entire class. It is also often used with static methods, where storing the dependency reference is inconvenient or sometimes even impossible.

The pattern is easy to implement and all it takes is a method which accepts a dependency as a parameter:

public void Export(IDataWriter dataWriter)

A typical scenario is that the dependency is used by the method in combination with some value:

public static string GetCountryName(Coordinates location, IGeoCoder geoCoder)

You may have come across the method injection pattern in the .NET framework as well. One example is the XmlSerializer.Serialize method:

public void Serialize(Stream stream, object o);

The XmlSerializer.Serialize method requires an instance of a concrete implementation of the abstract Stream class to be passed into it, in order for it to do its job, allowing us to serialize the object either to file, memory, socket, or any other target you can find or create a Stream descendant for.

Just like with constructor and property injection, it is best practice to use a guard clause if the dependency is required:

public static string GetCountryName(Coordinates location, IGeoCoder geoCoder)
{
    if (geoCoder == null)
    {
        throw new ArgumentNullException("geoCoder");
    }
    
    // use dependency
}

Ambient Context

Some cross-cutting concerns are required by almost all the classes in an application. Passing these types of dependencies using constructor, property or method injection can cause the API to become polluted. The Ambient Context pattern solves this problem by making the dependency available to any consumer via a static property or a method.

Since Ambient Context is tricky to implement and should only be used in the rarest of circumstances, it is beyond the scope of this article. However, if you are interested in the concept, the book Dependency Injection in .NET by Mark Seemann, has an excellent and detailed description of the pattern in chapter 4.4.

DI Containers

The problem with dependencies is that they are lot like dominoes: One dependency, might depend on another which in turn depends on another and so on. This hierarchy of nested dependencies can grow fairly quickly, and if you have to manually create each dependency using the new keyword then your code might eventually become hard to read.

Consider the following class:

public class CustomerService
{
    ICustomerRepository _customerRepository;
    IGeoCoder _geoCoder;
    
    public CustomerService(ICustomerRepository customerRepository, IGeoCoder geoCoder)
    {
        if (customerRepository == null)
        {
            throw new ArgumentNullException("customerRepository");
        }
        
        if (geoCoder == null)
        {
            throw new ArgumentNullException("geoCoder");
        }
        
        _customerRepository = customerRepository;
        _geoCoder = geoCoder;
    }       
}

This is a pretty standard class with two dependencies, using the constructor injection pattern. But in order to instantiate the class, we need the following code:

IDatabaseConnection databaseConnection = new SqlServerDatabaseConnection();
ICustomerRepository customerRepository = new CustomerRepository(databaseConnection);
IGeoCoder geoCoder = new GoogleGeoCoder();

CustomerService customerService = new CustomerService(customerRepository, geoCoder);

So in order to instantiate this simple class, which has only two dependencies, we already need to create three other objects to fulfill it’s dependency requirements. It’s not hard to imagine that this can quickly spiral out of control.

This is where DI Containers, or Inversion of Control (IoC) Containers come into play. A DI Container is a software library that can help create dependencies, manage their lifetimes and inject them automatically whenever it is required. Just like any framework, a DI Container provides you with an API that you can use to compose objects, which is just a fancy term for creating instances and providing them with the dependencies they require — You can also think of it as connecting the different components of your application.

Before you can use a DI Container you have to configure it, by registering the interfaces and what class should be created when an instance for that interface is encountered or requested. In most DI Container libraries this can be done with an XML file or through code either explicitly or by convention, which is sometimes also called auto-registration.
When configuration by convention (or auto-registration) is used, the framework will use a specified convention to automatically find the class that should be created based on the name of the encountered interface.

There’s nothing magical about DI Containers and behind the scenes they use reflection to analyze the requested or encountered classes and figure out which dependencies are needed. The process of composing the object graph is called auto-wiring.

It is possible to write your own container, but with so many good DI Container libraries out there already it is best to simply use one of those instead. Some popular DI Container libraries for the .NET Framework are: Microsoft Unity, Castle Windsor, Autofac, Ninject, StructureMap and Spring.NET.

Resolving is the action of requesting an instance from the container, and triggering the auto-wiring. The way this is done is different for every library, but most of them are very similar. Here’s an example using the Microsoft Unity framework:

ICustomerService customerService = container.Resolve();

See how much easier that is? All of the dependencies that we had to manually create in the first example are now automatically created and injected into the constructor for us.

One important thing to remember however is that you don’t need to use a DI Container in order to do Dependency Injection, this is often referred to as Poor Man DI or using more accurate and friendlier sounding terminology: Pure DI. Both approaches, using a DI Container and opting not to use one, have advantages and disadvantages. More information on that can be found here.

Composition Root

Although you can potentially use a DI Container from anywhere in your code, that is generally considered a bad idea. Instead all the work you do with the container should be concentrated in a single place. This place is called the *Composition Root and is where all the modules are composed together. It should also be the only spot in your code where you use the container and resolve objects.

If you prefer, the Composition Root can be spread out across multiple classes, but only as long as they all reside in a single module.

The Composition Root should be placed as close to the application’s entry point as possible. This entry point depends on the .NET Application type:

  • For a console application this is the Main method.
  • An ASP.NET web application has the Application_Start event handler in the Global.asax.
  • WPF applications can use the OnStartup event handler in the App.xaml.cs.
  • Windows Forms applications can also use the Main method.
  • WCF services have several entry points, but most commonly a custom ServiceHostFactory is used.

There are more .NET application types, but each of them has one module which contains the entry point, or root of the application.

Of course, having the Composition Root in one place has the effect that the module that contains it has to know about all of the other assemblies required to compose the application. This is fine. After all, this is the place where the entire application is strung together and decisions about which concrete implementations are to be used are made and the dependencies are provided to the other modules.

Register, Resolve and Release

Not only the place where we use our container is important, but also how we use it matters. For this we follow the three phases of the Register, Resolve and Release pattern.

  1. Register: In order for us to use our container we have to configure it by registering our types.
  2. Resolve: Then we need to actually compose our object graph.
  3. Release: Finally, when we’re done we need to clean-up and dispose our object graph.

When using the pattern, it is imperative that we follow the steps in this strict sequence. As soon as you’ve completed one phase, and started on the next you can’t move back anymore. This is to prevent you from reconfiguring your container after you’ve already started resolving your object graph. So once your configuration is done, you’ve basically committed to it.

Also note that, composing an object graph is a single method call. In other words, we can only call the Resolve method once, which is fine because if we use it correctly, it will build the entire object graph for us.

Officially, with this pattern, every phase should consist of a single, atomic action on the container. But while some DI Container libraries do allow you to build a configuration first and hand that to the container, others don’t quite make it so easy. In the latter case, it is advisable to create a custom class that encapsulates the configuration into a single method. But, while we should strictly adhere to the single method call principle for the Resolve and the Release phases, it is okay to bend the rules for the Registration phase.

Microsoft Unity Example

To show some of this theory applied in a more practical example, I’ve created a small demo application using Windows Presentation Foundation (WPF) and version 5 of the Microsoft Unity container library.

The demo application is a basic example using several stub interfaces and classes to simulate multiple dependencies. All it does is show a window, inject a view-model into the window constructor and setup the required dependencies using a DI container. A dummy service called CustomerService loads a list of customers which are then shown in the window and there’s a button on the window which can show a dialog using the DialogService.

Since most container libraries are very similar, it doesn’t matter what container I use in the example and most of the information should apply to whichever container you want to use.

The Microsoft Unity library can be found and downloaded as a nuget package from here: https://www.nuget.org/packages/Unity.Container/. Like most container libraries, it is free to use, both for personal and commercial projects.

To work with Unity, we need create a container, register our type-mapping on that container and finally resolve our object graph. Making the simplest use-case look a little like this:

UnityContainer container = new UnityContainer();
container.RegisterType

Creating the container is fairly straightforward, and registering a type-mapping can either be done with the RegisterType method if we want the container to create instances for us, which is the most common case, or with the RegisterInstance method if we just want to add an already created instance to the container. With the container configured, we can use the generic Resolve method to resolve the requested instance and compose our object graph.

Of course, we also need to clean up our container when we’re finished with it, in order to satisfy the Release phase:

container.Dispose();

The container can also manage the lifetime of the objects for us. Since not all types require the same lifetime management, we can specify how a type should be treated.

In Unity, the default lifetime of an instance is transient, which means that a new instance is created every time a dependency of that type is encountered. So if you have five objects that depend on the IDatabaseConnection interface, and you have mapped it to an SqlDatabaseConnection concrete class, with the default or transient lifetime, then each of these objects will receive a new instance of the SqlDatabaseConnection class, resulting in five instances. With transient lifetime the container also doesn’t keep track of the instance it creates, meaning that it will not do any lifetime management for that instance; so it is essentially a fire-and-forget mechanism.

Aside from the default, transient lifetime there are several more lifetime types available:

Lifetime Description
Transient Instances aren’t tracked by the container (default lifetime)
Container Controlled Registers an existing object as a singleton instance.
Per Resolve A happy medium between Transient and Container Controller. Every time an object graph is resolved, only a single instance of this type will exist in that object graph. Instances aren’t tracked by the container.
Hierarchical Lifetime is shared with the container and returns the same instance of the registered type or object each time. When there are child containers, each child resolves its own instance of the object and does not share one with the parent.
Per Thread On a per-thread basis, the same instance of the registered type or object each time. Instances aren’t tracked by the container.
Externally Controlled Registers objects on a singleton basis, but provides generic support for externally managed lifetimes by storing only weak references.

What lifetime type you should choose for your mapping, entirely depends on how the object is supposed to be used. Configuring lifetime is done by providing the RegisterType method with a LifeTimeManager object. For example to make the IDialogService mapping in the basic example a singleton instance we can do so as follows:

container.RegisterType

Similarly, if we want it to be hierarchical we can assign it a HierarchicalLifeTimeManager object:

container.RegisterType

The entry point of a Windows Presentation Foundation (WPF) application is the OnStartup event in the App.xaml.cs file, making it our Composition Root:

public partial class App : Application
{
    private UnityContainer _container;

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        // Register
        _container = Bootstrapper.Register();

        // Resolve
        MainWindow mainWindow = _container.Resolve();

        Application.Current.MainWindow = mainWindow;
        mainWindow.Show();
    }

    protected override void OnExit(ExitEventArgs e)
    {
        base.OnExit(e);

        // Release
        _container.Dispose();
    }
}

Here our three phases Register, Resolve and Release are clearly visible. In order to neatly condense the Register phase into a single method call, I created a separate, static Bootstrapper class with a Register method which contains all of the code required to setup our container:

public static class Bootstrapper
{
    public static UnityContainer Register()
    {
        UnityContainer container = new UnityContainer();

        string connectionString = "Server=127.0.0.1;Database=MyDataBase;Trusted_Connection=True;";
        container.RegisterType<IDatabaseConnection, SqlServerDatabaseConnection>(new ContainerControlledLifetimeManager(), new InjectionConstructor(connectionString));

        container.RegisterType<ICustomerRepository, CustomerRepository>(new ContainerControlledLifetimeManager());
        container.RegisterType<ICustomerService, CustomerService>(new ContainerControlledLifetimeManager());

        container.RegisterType<IDialogService, DialogService>(new ContainerControlledLifetimeManager());

        container.RegisterType<IMainWindowViewModel, MainWindowViewModel>();

        return container;
    }     
}

The only new thing here is the InjectionConstructor, which allows you to pass a custom parameter to the constructor of a registered type. In this case it is used to pass the connection string to the SqlServerDatabaseConnection class.

And that is pretty much all there is to it for this simple demo application. If you want to take a look at the full source code of the example, it can be downloaded here.

Resources

Reducing Coupling – Martin Fowler

Dependency Injection in .NET – Mark Seemann

Coupling (computer programming) – Wikipedia

Old Measures for New Services – Steve Vinoski

Dependency Injection: The Property Injection Pattern – Jeremy Bytes

Design Patterns: Elements of Reusable Object-Oriented Software – Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides

Pure DI – Mark Seemann

Compose object graphs with confidence – Mark Seemann

When to use a DI Container – Mark Seemann

  May 1, 2018 16:00
  May 1, 2018 16:08
  .NET Development, C# Programming
  , , ,  

Contact

Do you want to work together on a project, have questions about my work or just want to say hello?
Feel free to send me an email at hello@armandpostma.com or use the contact form below.

Pin It on Pinterest