0

Can I use DI container down in the hierarchy to create new objects? For each DI container you setup dependencies and then say getInstance by type and it creates the instance properly. Also, you can read lots of articles that explain that DI container should be on the top of the hierarchy in the main function and it should not be passed around or a singleton. But what if I want to get an instance from the container down in the hierarchy of my objects?

Narek
  • 38,779
  • 79
  • 233
  • 389
  • Please provide some pseudo-code. Its hard to understand what kind of hierarchy do you mean: call, object, type, context? – Basilevs Oct 18 '15 at 06:47
  • *Can I use DI container down in the hierarchy?* You can, but [you shouldn't](http://stackoverflow.com/a/2386636/126014). – Mark Seemann Oct 18 '15 at 09:54
  • *what if I want to get an instance from the container down in the hierarchy of my objects?* Why would you want to do that? What's the use case? – Mark Seemann Oct 18 '15 at 09:55
  • 1
    @MarkSeemann: I think you are interpreting the question to strictly. I think that OP not necessarily want to apply Service Location, but would like to have things like a proxy, dispatcher or factory that allows resolving part of the graph at runtime. – Steven Oct 18 '15 at 18:27
  • @MarkSeemann because at some point my object graph should change. – Narek Oct 19 '15 at 11:56
  • 1
    @Narek: No, after the application started, the object graphs should be fixed and should never change in shape or structure. Changing how object graphs are constructed at runtime makes it really hard to verify the correctness of the graph, and making changes to your container at runtime will cause [all sorts of grief](https://simpleinjector.readthedocs.org/en/latest/decisions.html#container-is-locked). If you still think this is required, please post a new question here on SO, and I will prove to you this isn't needed. – Steven Oct 19 '15 at 13:44
  • @Steven I think you are going to suggest injecting Factories and create other object runtime, right? – Narek Oct 19 '15 at 14:10
  • @Narek: No, absolutely not. When it comes to Dependency Injection, I think factories are almost never the right solution. – Steven Oct 19 '15 at 14:25
  • @Steven creating the question. http://stackoverflow.com/questions/33217145/object-graph-construction-at-runtime :) – Narek Oct 19 '15 at 14:32

1 Answers1

1

Avoid letting application code (other than the start-up code) take a direct dependency on the container or an abstraction over the container; this is an anti-pattern known as Service Locator. The start-up code is commonly referred to as the Composition Root.

The Composition Root is a separate layer in your application. This layer lies on top of the other layers, such as Presentation Layer and Business Layer.

This doesn't however mean that you can't use the container to create parts of the object graph in a lazy manner after some condition. Here's an example:

// Defined in a shared library of your application, accessible to all other
// code in your application.
public interface ICommandProcessor
{
    public void Process(object command);
}

Possible usage of this interface is as follows:

this.commandProcessor.Process(new ShipOrderCommand(orderId));

While the abstraction doesn't note anything about the use of a possible container, the implementation of this abstraction can still depend on one. But since application code should not depend on the container, this implementation should be defined inside the Composition Root (the start-up path of your application). This allows the application to stay oblivious off the existence of such tool, while the container can still be used to resolve object graphs. Here is an example implementation:

public class CommandProcessor : ICommandProcessor
{
    private readonly Container container;
    public CommandProcessor(Container container) {
        this.container = container;
    }
    public void Process(object command) {
        Type handlerType = typeof(ICommandHandler<>).MakeGenericType(command.GetType());
        dynamic handler = this.container.GetInstance(handlerType);
        handler.Handle((dynamic)command);
    }
}

So long story short, you can use the container for creating object graphs in a delayed fashion, as long as the only layer in your application that uses the Container is your Composition Root.

Steven
  • 166,672
  • 24
  • 332
  • 435
  • What you mean by saying **application code itself doesn't have to call GetInstance**? How you define application code and why `Process` method of class `CommandProcessor` is not considered application code? – Narek Oct 19 '15 at 05:09
  • @Narek: Although the Composition Root is patt of the code you writr for your application, we view it as a bit different and often talk about the Composition Root vs te rest of your application. While the CR may depend on the Container, the remainder of your application may not. – Steven Oct 19 '15 at 06:32
  • Sounds like `Process` method is **the remainder of your application**, right? So it looks, you say application code should not use, but you use it in application code. – Narek Oct 19 '15 at 11:51
  • @Narek: The `Process` method's code is part of the Composition Root, while the `ICommandProcessor` is defined in a core library of the application, so other code can depend on it. – Steven Oct 19 '15 at 11:54
  • How `Process` method's code can be part of CR? It sounds to me, like some class's method code is a part of the `void main()` function is C++. – Narek Oct 19 '15 at 11:58
  • @Narek: Composition Root is a layer. I updated my answer to describe this. Hopefully this makes everything a bit more clear. – Steven Oct 19 '15 at 12:10
  • Still does not make sense to me, sorry. For me CR is on function where you create your app instance and wire up all objects. What you describe, does not fit in my understandings about the CR. – Narek Oct 19 '15 at 12:14
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/92725/discussion-between-steven-and-narek). – Steven Oct 19 '15 at 12:19