4

I have a console app that has references to many dlls. The console app needs to instantiate objects in these dlls. The dlls have dependencies that I'd like to inject into their constructors. My requirement is to do all registrations in the console app - it's the composition root. I can get this far, but how can I persist these registrations into the libraries without passing/referencing the UnityContainer?

I want to avoid a service locator pattern and purely use constructor/method injection. None of this, if possible:

_container.Resolve<IData>()  // not what I want

Here's what I've got in the console app:

            static IUnityContainer _container;

            static void Main(string[] args)
                    {
                        LoadContainer();
                        var worker = new Worker(_container.Resolve<IData>()); // I don't like this
                        worker.Start();
                    }

            private static void LoadContainer()
                    {
                        _container = new UnityContainer();

                        // This will register all types with a ISample/Sample naming convention 
                        _container.RegisterTypes(
                            AllClasses.FromLoadedAssemblies(),
                            WithMappings.FromMatchingInterface,
                            WithName.Default);
                    }

When I'm in the class Worker, how would I inject dependencies to other class's constructors? In MVC I can easily handle this in the UnityConfig, but can't figure it out for this scenario. I feel that I should be able to bootstrap everything in the console and be done with it. Are there Unity extensions that can help with this?

7
  • Isn't Unity (or any other IoC container, for that matter) a service locator by definition? Doesn't the notion of direct constructor injection preclude the use of an IoC container? Commented May 5, 2014 at 18:47
  • @RobertHarvey...It's certainly part of the definition, but doesn't define the container. I can do my DI manually from the console without a container for classes that I directly interacts with, but what about the ones it doesn't? Service locator just seems like the wrong approach - even though I've done my fair share of it. Commented May 5, 2014 at 18:55
  • And you're saying that you don't want to use a UnityConfig? Commented May 5, 2014 at 18:56
  • @RobertHarvey...I use UnityConfig in my MVC projects. Is it possible to use this approach in windows apps? Are referring to using the app.config to do the registrations? I'm certainly not opposed to either although the app.config approach can become messy. Commented May 5, 2014 at 19:01
  • 1
    @RobertHarvey...In MVC we have UnityWebActivator to integrate Unity into the pipeline. It's not going to work in a console app. Commented May 5, 2014 at 19:22

2 Answers 2

3

Assuming Worker is registered in the container, either as a concrete type or IWorker:

var worker = _container.Resolve<IWorker>();

or

var worker = _container.Resolve<Worker>();

and then:

worker.Start();

That should be all you need if Worker is at the top of your object graph, and all dependencies flow from it. This is not service location, as you are only calling Resolve() once, and doing so in your composition root. Only the composition root knows about your container.

Edit

From your comments--so assuming this is your setup:

public class Root
{
    private readonly A _a;

    public Root(A a)
    {
        if (a == null) throw new ArgumentNullException("a");
        _a = a;
    }
}

public class A
{
    private readonly B _b;

    public A(B b)
    {
        if (b == null) throw new ArgumentNullException("b");
        _b = b;
    }
}

public class B
{
    private readonly C _c;

    public B(C c)
    {
        if (c == null) throw new ArgumentNullException("c");
        _c = c;
    }
}

public class C
{

}

Assuming you had all the registrations set up correctly in Unity, you would just Resolve at the top of the graph:

var root = _container.Resolve<Root>();

The container would do the rest. "root" is now a container-managed object, and because of this the container can resolve the full graph of dependencies.

This is constructor injection, not service location. The only object in the system that knows anything about the container is the composition root--the only place you call Resolve() is in the Main() method.

Again, I may be misunderstanding something about your question, but what I am describing is pretty much the basic use case of DI + constructor injection.

Sign up to request clarification or add additional context in comments.

7 Comments

I don't see how this will work. As the object graph gets many levels deep, how are dependencies resolved? Even if all registrations are done at the root level, how will dependencies be resolved without a container?
When you create the worker using the container, the worker will be "container managed" from that point forward. It will have its dependencies resolved by the container, and it will have its dependencies' dependencies resolved by the container, etc. This is how DI frameworks work. You only need to utilize the container at the top of the object graph (in your composition root).
Unless the container is passed around the object graph and service location is used, I can't see how this can work. In my console app situation, how can objects handle DI when they don't have access to the container?
Their "parent" object is container-managed. The container resolves the full chain from the top level downward when you resolve the Worker class. So the whole chain of objects is managed by the container. This is precisely the point of using a DI framework.
Maybe I'm not understanding your question completely. Are the objects you want to instantiate not part of the same object graph as the worker? If they are dependencies or sub-dependencies (or deeper dependencies) of the worker object, there is no reason why this won't work.
|
1

You set up local factories (aka dependency resolvers) and configure them in the Composition Root. In other words, if you are in Foo class and you need Bar, you use BarFactory or BarResolver that is configured to use Unity but can be reconfigured to use anything without the need to change client code (what changes is the configuration in the CR).

http://www.wiktorzychla.com/2012/12/di-factories-and-composition-root.html

4 Comments

Should there be one factory per class? Where do you keep these factories? In an infrastructure-type library?
There doesn't have to be one factory per class. A local Dependency Resolver could act as a factory for a family of local classes. The factory (aka resolver) is kept in the very same library that classes it creates.
I just implemented your suggestion and it looks good. I'm confused about the dependency resolver part and how to implement it.
Dependency Resolver is just another name for such local factory.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.