Skip to content

Latest commit

 

History

History
170 lines (121 loc) · 7.89 KB

3. Dependency Injection.md

File metadata and controls

170 lines (121 loc) · 7.89 KB

Dependency Injection

Dependency Injection (DI) is a loaded name and may sound complicated but as [James Shore] (http://www.jamesshore.com/Blog/Dependency-Injection-Demystified.html) said: '"Dependency Injection" is a 25-dollar term for a 5-cent concept. [...] Dependency injection means giving an object its instance variables. Really. That's it.".

Dependency Injection is an expression coined by [Martin Fowler] (http://martinfowler.com/). Dependency injection decouples classes by removing dependencies on specific implementations and thus allows classes to rely on abstractions instead. There are three ways to inject dependencies, via constructor injection, property injection or parameter injection. Usually a framework such as [StructureMap] (http://docs.structuremap.net/) or [Ninject] (http://www.ninject.org/) is used to deal with the instancing and providing of the implementations. DI makes code more maintainable. When an implementation needs to be replaced, due to changes in requirements, the developer does not have to modify the core of the application but only create a new implementation of the interface and then inject that instead of the previous one which is a very helpful tool when trying to conform to the Open/Closed Principle. Another situation is where the specific implementation of an interface is only known during runtime, DI can be used to provide appropriate implementation in those scenarios.

When using DI you are forced to use interfaces, which comes with the bonus of code being more testable. The interfaces can be used to create mocks of the implementation, thus allowing developers to test classes in isolation, but mocking will not be covered in this section.

Constructor Injection

The most common way to inject dependencies is with a constructor. To do this you need to have a constructor with an argument to accept the dependency:

public class Repository
{
    private readonly IDbContext _context;

    public Repository(IDbContext context)
    {
        _context = context;
    }

    // ...
}

Advantages include:

  1. If the the class is dependant on the dependency and will break without it, this way of injecting will make sure the class is not created without it.

  2. Since the constructor is only called once, when the object is created, you can be sure that through the entire lifetime of the object, it will keep the same dependency. That is if you do not have some other methods to change the dependency.

On the other hand, the disadvantage is that if you need to extend the class and override the constructor you're going to run in to some trouble.

Setter injection

Setter injections are made, not surprisingly, with setter functions.

public class Repository
{
    private readonly IDbContext _context;

    public Repository()
    {

    }

    public void setContext(IDbContext context)
    {
        _context = context;
    }
}

This method has some advantages and some disadvantages.

The advantages include:

  1. If the dependency is not required for the class to work, it is much easier to use the setter since you can change it any time and the class becomes, dare I say, more dynamic.

  2. If you do not need the dependency you do not have to call the setter so it becomes optional.

The disadvantages include:

  1. Since you do not have to call the setter, you'll have to check if the dependency is set or not. This entails having to write some extra lines of error checking code.

  2. The setter can be called at any time, not just at the construction, so you can not be sure if the dependency is the same one as you intend it to be at any given time. Again adding error checking line to your code.

Property Injection

Simply making the dependency a property of the class itself. This way it can be set anywhere at any time.

public class Repository
{
    public IDbContext _context;

    public Repository()
    {

    }

    // ...

}

Most of the time this is not the recommended way to inject. It is similar to the setter injection but this way you can't control when the dependency is changed and you have no good way of checking if the change was legal or not when it happens. This means that you have to test the dependency before you use it.

On the other hand this can be useful when you are either using a service container or working with third party libraries and need to get access to their properties.

Poor man's DI

First, let us look at a "poor man's version" of DI, where we support DI by ensuring our class can be constructed in two ways: a) by passing in a dependency via a constructor parameter, or b) by using a parameterless constructor, in which case we will use a default dependency:

public class SomeServiceProvider
{
    private readonly IUnitOfWork _uow;
    private readonly IRepository<EntitClassA> _As;
    private readonly IRepository<EntityClassB> _Bs;
    
    public SomeServiceProvider()
    {
        _uow = new UnitOfWork<AppDataContext>();
        _As = _uow.GetRepository<EntityClassA>();
        _Bs = _uow.GetRepository<EntityClassB>();
        // etc., depending on how many tables this service provider needs access to
    }
    
    public SomeServiceProvider(IUnitOfWork uow)
    {
        _uow = uow;
        _As = _uow.GetRepository<EntityClassA>();
        _Bs = _uow.GetRepository<EntityClassB>();
        // etc., depending on how many tables this service provider needs access to
    }
}

This version of SomeServiceProvider does support DI, but does so without the use of any DI framework. In this implementation, we can either instantiate it with a reference to some IUnitOfWork implementation, or use the parameterless constructor, in which case the class will use the concrete UnitOfWork class. This means we can either use the SomeServiceProvider class in our "regular" code (i.e. in the Web API project), or in a unit test project, which would provide a different UnitOfWork, which would use a mock data source (which will be covered later).

Note: the NInject wiki has an excellent article explaining this as well.

NInject

As you can see, having to specify multiple constructors for each class which is supposed to support DI can become bloated as the number of classes grows. When using frameworks such as NDepends, we specify in one place what concrete implementations should be used for a given interface which some classes depend upon. In the example above, IUnitOfWork is such a dependency.

Adding support for NInject in a Web API project does currently involve some boilerplate code. The process is explained here. First, you need to add a reference to Ninject.Web.WebApi. Then, we should add at least one class which inherits from NinjectModule, and overrides the Load() function:

        public override void Load()
        {
            this.Bind<IUnitOfWork>().To<UnitOfWork<AppDataContext>>().InRequestScope();
        }

By using a framework such as NInject, the process of creating an instance of an object with dependencies is slightly different from this:

  var service = new SomeServiceProvider( /* ... what should we pass in here?? ...*/ );

Instead, we should now use the service provided by the Kernel:

IKernel kernel = new StandardKernel();
var service = kernel.Get<SomeServiceProvider>();

NInject will figure out what constructors exist for the given type (i.e. SomeServiceProvider in this case), and check if it can inject all the dependencies for it. This process is explained here.

We will rarely have to use the kernel ourselves, as long as we place the dependencies into our controllers, since the Web API framework will then use the DI framework internally.