Question

I read with interest this article which states:

A DI Container should only be referenced from the Composition Root. All other modules should have no reference to the container.

This means that all the application code relies solely on Constructor Injection (or other injection patterns), but is never composed. Only at the entry point of the application is the entire object graph finally composed.

I take it to mean all instances should be injected, never instantiated by anything other than the IoC container.

Under this pattern, this is not allowed:

class MyClass {
    void SomeMethod() {
        var w = new Worker();
        w.DoSomething();
    }
}

Instead it should look more like this:

class MyClass {
    protected readonly IWorker _worker;
    public MyClass(IWorker worker) {
        _worker = worker;
    }
    void SomeMethod() {
        _worker.DoSomething();
    }
}

This works fine if I only need one instance of Worker per instance of MyClass. But what if Worker is stateful (or worse, Disposable) and I need a new instance each time SomeMethod is called?

I could do something like this:

class MyClass {
    protected readonly IUnityContainer _container;
    public MyClass(IUnityContainer container) {
        _container = container;
    }
    void SomeMethod() {
        using (var w = _container.Resolve<IWorker>()) {
            w.DoSomething();
        }
    }
}

But that technique is frowned upon by this article, and also it violates the principle that the container should only be referenced from the composition root.

I could inject a factory:

class MyClass {
    protected readonly IWorkerFactory _factory;
    public MyClass(IWorkerFactor factory) {
        _factory = factory;
    }
    void SomeMethod() {
        using (var w = _factory.Create<IWorker>()) {
            w.DoSomething();
        }
    }
}

...which seems to address the issue. But then when I go to write the factory, I have to reference the container again:

class WorkerFactory : IWorkerFactory
{
    protected readonly IUnityContainer _container;

    public WorkerFactory(IUnityContainer container) {
        _container = container;
    }

    public T Create<T>() where T : IWorker {
        return _container.Resolve<T>();
    }
}

...so really, it seems, I have moved the problem, not solved it.

If it is true that "A DI Container should only be referenced from the Composition Root," I don't see how that is possible for per-method-call instantiation.

How do I support per-method-call instantiation without referencing the container from outside the composition root?

Was it helpful?

Solution

Most IoC containers will provide a method for automatically implementing a factory. See for example:

The IoC container will create an instance of a factory that will, if configured properly, return a new object with every call to a method.

This works, because the container will generate code that for the factory that references the container and uses it to satisfy the dependencies of the objects you're creating. If your IoC container is not so mature and doesn't have that facility then you'll need to write your own factory, and that factory will likely have to reference the IoC container directly. I would say this case is an exception to the rule, and as long as your references to the container are kept sequestered in your factory implementations and don't leak out anywhere, then you will still be following the spirit of the rule.

OTHER TIPS

First off, instantiation per request is often troublesome for apps. It creates a lot of garbage. It tends to be slow. For scalable applications, it's often avoided. Per method call will be even worse, especially since IoC resolution and instantiation will hit on reflection and cause problems.

Second, a factory with Create<T> isn't really a factory, but a ServiceLocator. They're generally frowned upon as they grow to be God objects.

All that said, instead of putting an IWorker into the IoC container, you can put a Func<IWorker> instead (or a strategy interface, or a more traditional factory). The consumer can then instantiate the worker as needed. Its dependencies in turn should be static, breaking the need to go back to the container each time. Instead, they've had their dependencies passed into them when you set everything up for the container.

And frankly, if the factory needs a reference to the container to resolve some dependencies (while hiding that reference in the implementation details of the factory), that isn't the worst thing in the world. Guidelines are there to help you, not handcuff you.

I think your reasoning is sound up and including this point:

But then when I go to write the factory, I have to reference the container again:

class WorkerFactory : IWorkerFactory
{
    protected readonly IUnityContainer _container;

    public WorkerFactory(IUnityContainer container) {
        _container = container;
    }

    public T Create<T>() where T : IWorker {
        return _container.Resolve<T>();
    }
}

...so really, it seems, I have moved the problem, not solved it.

I don't agree that you haven't solved the problem - consider some of the issues raised by Mark Seemann, and how your solution addresses those:

  • The container is no longer a dependency of those service classes which contain 'real' business logic.
  • The WorkerFactory is targeted specifically at those classes which actually need to create an IWorker, and is only provided to those classes.
  • WorkerFactory adheres to SRP - it is only responsible for creating short-lived IWorker objects for the business/service classes.
  • The constructors to domain/service classes no longer hide their dependencies behind the IUnityContainer interface.
  • The visibility of methods such as RegisterInstance and RegisterType is minimised. Service classes are no longer able to sneakily "go rogue" by tampering with the IoC container.
  • On a more subjective note, the purpose and usage of IWorkerFactory looks more idiomatic for object creation (Principle of Least Astonishment).

Erik linked to examples using AutoFac, Windsor and Ninject which provide an out-of-the box solution which does the same and eliminates the hand-rolled WorkerFactory, but seems to accomplish the same job, in (presumably) the same way.

For IoC containers such as Unity which don't have something like this out-of-the box (please correct me if I'm wrong about that), it should be possible to write a small extension similar to WorkerFactory yet more widely reusable:

public class AbstractFactory<T> : IFactory<T>
{
    protected readonly IUnityContainer _container;

    public AbstractFactory(IUnityContainer container) {
        _container = container;
    }

    public T Create()  {
        return _container.Resolve<T>();
    }
}

Unity configuration:

  // I believe this is the correct syntax, but not tested!  
  // the concept should work with Unity anyway.
  container.RegisterType(typeof(IFactory<>), typeof(AbstractFactory<>));
  container.RegisterType(typeof(IWorker), typeof(Worker));

The code which needs to create short-lived instances looks almost the same:

public class MyClass
{
    private readonly IFactory<IWorker> _workerFactory;

    public MyClass(IFactory<IWorker> workerFactory)
    {
        _workerFactory = workerFactory;
    }
}

Also related: Mark Seemann has made quite a few contributions on this subject over at SO (A list of his answers here: https://stackoverflow.com/questions/2280170/why-do-we-need-abstract-factory-design-pattern/2280289#2280289) There seem to be several answers where he suggests plain-old new inside an Abstract Factory.

On another related note, Mark's book Dependency Injection in .NET discusses short-lived dependencies (Chapter 6), and particularly "boundary" objects whose lifetime needs to be managed and/or resources need to be cleaned up, such as DbConnection, TcpClient, or any other similar class which operates 'close to the metal'.

In his book, Mark argues those kinds of classes shouldn't be injected or even created with a factory, and also shouldn't be exposed to service classes because their interfaces are geared towards technical concerns not business concerns. I.e. a business logic class should never be handling the nuances of a DbConnection with it's connection string, timeout failures, retries, etc.

The book suggests ignoring IoC altogether for these types of "boundary" objects, and wrapping them with abstractions (ideally stateless abstractions). Those abstractions which hide away the nitty-gritty lifetime/resource management would be responsible for new'ing (and Dispose()'ing) the low-level object, while the IoC container would inject the abstraction into the service class, which only cares about high-level concerns such as executing a command or query.

Licensed under: CC-BY-SA with attribution
scroll top