Dependency Injection – Using Containers at the Root of an Application

cdependenciesdependency-injectiondesignservice-locator

normally, I'll use a dependency injection container (unity) in c# like this example:

class SomeClass
{
    private readonly ILogger _logger;

    public SomeClass()
    {
        _logger = DependencyContainer.Resolve<ILogger>();
    }

    public void DoSomething()
    {
        var someOtherClass = DependencContainer.Resolve();
        someOtherClass().whatElseEver();
    }
}

Yesterday, I've read some articles about correct dependency injection with a di container. After this, I know that my example is totally bad. This is not dependency injection this is just something like a service locator.

Okay, how to solve this? I think with constructor injection you can solve this problem easily:

class SomeClass
{
    private readonly ILogger _logger;
    private readonly ISomeOtherClass _someOtherClass;

    public SomeClass(ILogger logger, ISomeOtherClass someOtherClass)
    {
        _logger = logger;
        _someOtherClass = someOtherClass;
    }

    public void DoSomething()
    {
        _someOtherClass().whatElseEver();
    }
}

Now I have the correct implementation of the dependency injection principle.
But how to wire up all these dependencies? I have a caller class which resolve all the required decencies of the class "SomeClass":

class SomeClassCaller
{
    public void DoSomething()
    {
        var logger = DependencyContainer.Resolve<ILogger>();
        var someOtherClass = DependencyContainer.Resolve();

        var someClass = new SomeClass(logger, someOtherClass);
        someClass.DoSomething();
    }
}

But this example still use a dependency container as a service locator, which is bad. In nearly every article about this, I've read, that the dependency container should only be used, at the application root/entry points, is this correct?

That means, no class should have the ability the resolve some dependencies with a "service locator" on the fly, like the logger. I've to inject the ILogger into nearly every class through the constructor, to avoid this problem, correct? This way feels really bad, if I take the ILogger through maybe 10 classes into every constructor, isn't it?

So, I've to use a dependencies container only, if I've a complex dependencie graph?

Can someone give me an example how it looks like, if you use a dependency container, only at the root of an application?

Best Answer

Consider these classes, and their dependencies explicitly listed as argumetns to the constructor.

class SomeClass {
    public SomeClass(IFoo foo, IBar bar) {}
}

class Foo : IFoo {
    public Foo(IBaz baz) {}
}

class Bar : IBar {}

class Baz :IBaz {}

The Graph would look like this:

  • SomeClass
    • IFoo
      • IBaz
    • IBar

Now, assembling this by Hand means creating instances the whole object graph, with its dependencies:

var baz = new Baz();
var foo = new Foo(baz);
var bar = new Bar();
var someClass = new SomeClass(foo, bar);

Using an IOC container with constructor injection is not really different. The thing you have to grasp is: You pull on one end, and the graph will follow:

container.add(IFoo, Foo);
container.add(IBar, Bar);
container.add(IBaz, Baz);
container.add(ISomeClass, SomeClass);

// now pull on your "Entry Point"/"Bootstrap":
container.get(ISomeClass);

The container will resolve and inject dependencies as needed. You do not have to resolve anything by hand, with one exception: This is your entry point.