Is it better to create a singleton to access unity container or pass it through the application? [closed]
Asked Answered
V

4

49

I am dipping my toe into using a IoC framework and I have choosen to use Unity. One of the things that I still don't fully understand is how to resolve objects deeper into the application. I suspect I just haven't had the light bulb on moment that will make it clear.

So I am trying do something like the following in psuedo'ish code

void Workflow(IUnityContatiner contatiner, XPathNavigator someXml)
{
   testSuiteParser = container.Resolve<ITestSuiteParser>
   TestSuite testSuite = testSuiteParser.Parse(SomeXml) 
   // Do some mind blowing stuff here
}

So the testSuiteParser.Parse does the following

TestSuite Parse(XPathNavigator someXml)
{
    TestStuite testSuite = ??? // I want to get this from my Unity Container
    List<XPathNavigator> aListOfNodes = DoSomeThingToGetNodes(someXml)

    foreach (XPathNavigator blah in aListOfNodes)
    {
        //EDIT I want to get this from my Unity Container
        TestCase testCase = new TestCase() 
        testSuite.TestCase.Add(testCase);
    } 
}

I can see three options:

  1. Create a Singleton to store my unity container that I can access anywhere. I really am not a fan of this approach. Adding a dependency like that to use a dependency injection framework seems a little on the odd side.
  2. Pass the IUnityContainer to my TestSuiteParser class and every child of it (assume it is n levels deep or in reality about 3 levels deep). Passing IUnityContainer around everywhere just looks odd. I may just need to get over this.
  3. Have the light bulb moment on the right way to use Unity. Hoping someone can help flick the switch.

[EDIT] One of things that I wasn't clear on is that I want to create a new instance of test case for each iteration of the foreach statement. The example above needs to parse a test suite configuration and populate a collection of test case objects

Valera answered 5/3, 2010 at 12:1 Comment(1)
it's like asking if it's better to die in a fire or drown.Ecto
S
52

The correct approach to DI is to use Constructor Injection or another DI pattern (but Constructor Injection is the most common) to inject the dependencies into the consumer, irrespective of DI Container.

In your example, it looks like you require the dependencies TestSuite and TestCase, so your TestSuiteParser class should statically announce that it requires these dependencies by asking for them through its (only) constructor:

public class TestSuiteParser
{
    private readonly TestSuite testSuite;
    private readonly TestCase testCase;

    public TestSuiteParser(TestSuite testSuite, TestCase testCase)
    {
        if(testSuite == null)
        {
            throw new ArgumentNullException(testSuite);
        }
        if(testCase == null)
        {
            throw new ArgumentNullException(testCase);
        }

        this.testSuite = testSuite;
        this.testCase = testCase;
    }

    // ...
}

Notice how the combination of the readonly keyword and the Guard Clause protects the class' invariants, ensuring that the dependencies will be available to any successfully created instance of TestSuiteParser.

You can now implement the Parse method like this:

public TestSuite Parse(XPathNavigator someXml) 
{ 
    List<XPathNavigator> aListOfNodes = DoSomeThingToGetNodes(someXml) 

    foreach (XPathNavigator blah in aListOfNodes) 
    { 
        this.testSuite.TestCase.Add(this.testCase); 
    }  
} 

(however, I suspect that there may be more than one TestCase involved, in which case you may want to inject an Abstract Factory instead of a single TestCase.)

From your Composition Root, you can configure Unity (or any other container):

container.RegisterType<TestSuite, ConcreteTestSuite>();
container.RegisterType<TestCase, ConcreteTestCase>();
container.RegisterType<TestSuiteParser>();

var parser = container.Resolve<TestSuiteParser>();

When the container resolves TestSuiteParser, it understands the Constructor Injection pattern, so it Auto-Wires the instance with all its required dependencies.

Creating a Singleton container or passing the container around are just two variations of the Service Locator anti-pattern, so I wouldn't recommend that.

Slavophile answered 5/3, 2010 at 12:27 Comment(9)
So you are saying you shouldn't pass the container around, and you shouldn't have it Static. I'm out of options then. In many cases I can't simply inject dependencies because I won't know until after user input what I need to do. Example: I have buttons that open different types of windows. When user presses button A I wan't to be able to say Container.Resolve<BaseWindows>("StringTiedToButtonA"). So should I have this as some kind of a service I inject in?Infundibuliform
I'm saying that you should neither pass the container around or have it static. When you need to resolve a dependency from a run-time value, you can use an Abstract Factory. See e.g. https://mcmap.net/q/49894/-can-39-t-combine-factory-di/…Slavophile
Could you point to some place that explains this even better, like showing the container interaction as well. In your example you still need to have access to the container where you instantied the factory. How did the container get there?Infundibuliform
Wait I think I might be getting it. I should pass in IWindowFactory into the class instead of the Container. Might be a bit more abstraction then I would need but if things change I guess I will be happy I did it.Infundibuliform
@Ingó: The concrete factory is allowed to be as trivial as needed, the point of it being that it provides a late-created instance of something that needs lately-known info to be able to instantiate.Pasquale
@Stimul8d Fowler said as much himself (Singleton beeing a anti-pattern)Emulsify
I think this answer still doesn't answer the original question. In a Web application or request-based model, it is not required to pass the container around as you can stuff an instance (the only instance you'll use) of the container it into an application-level dictionary such as the HttpApplicationState. But how do the top-level classes (those nearest to the UI that need to compose) in your desktop application's get a reference to the container?Apis
To amplify the original question, how would the client code get a reference to the container where it resolves this line: var parser = container.Resolve<TestSuiteParser>();. IMHO, in a desktop application model, use any kind of IoC sparingly. Prefer using abstract factories in the case of desktop applications and use DI only very, very, very sparingly. And in most cases, it is okay to use the Service Locator in desktop apps to avoid passing the container around.Apis
@WaterCoolerv2 There's no reason to resort to the Service Locator anti-pattern, or to reference a container from outside the Composition Root. As you say, Constructor Injection, and the occasional Abstract Factory, is enough for all purposes.Slavophile
K
13

I am new to Dependency Injection and I also had this question. I was struggling to get my mind around DI, mainly because I was focusing on applying DI to just the one class that I was working on and once I had added the dependencies to the constructor, I immediately tried to find some way to get the unity container to the places where this class needed to be instantiated so that I could call the Resolve method on the class. As a result I was thinking along the lines of making the unity container globally available as a static or wrapping it in a singleton class.

I read the answers here and did not really understand what was being explained. What finally helped me "get it" was this article:

http://www.devtrends.co.uk/blog/how-not-to-do-dependency-injection-the-static-or-singleton-container

And this paragraph in particular was the "light bulb" moment:

"99% of your code base should have no knowledge of your IoC container. It is only the root class or bootstrapper that uses the container and even then, a single resolve call is all that is typically necessary to build your dependency graph and start the application or request."

This article helped me understand that I actually must not access the unity container all over the application, but only at the root of the application. So I must apply the DI principle repeatedly all the way back to the root class of the application.

Hope this helps others who are as confused as I was! :)

Koa answered 17/12, 2012 at 23:31 Comment(0)
V
4

You should not really need to use your container directly in very many places of your application. You should take all your dependencies in the constructor and not reach them from your methods. You example could be something like this:

public class TestSuiteParser : ITestSuiteParser {
    private TestSuite testSuite;

    public TestSuitParser(TestSuit testSuite) {
        this.testSuite = testSuite;
    }

    TestSuite Parse(XPathNavigator someXml)
    {
        List<XPathNavigator> aListOfNodes = DoSomeThingToGetNodes(someXml)

        foreach (XPathNavigator blah in aListOfNodes)
        {
            //I don't understand what you are trying to do here?
            TestCase testCase = ??? // I want to get this from my Unity Container
            testSuite.TestCase.Add(testCase);
        } 
    }
}

And then you do it the same way all over the application. You will, of course, at some point have to resolve something. In asp.net mvc for example this place is in the controller factory. That is the factory that creates the controller. In this factory you will use your container to resolve the parameters for your controller. But this is only one place in the whole application (probably some more places when you do more advanced stuff).

There is also a nice project called CommonServiceLocator. This is a project that has a shared interface for all the popular ioc containers so that you don't have a dependency on a specific container.

Vair answered 5/3, 2010 at 12:22 Comment(2)
Thanks for the response. I have updated my question. Does this clarify for you?Valera
@Valera Mark Seemann has that included in his answer. A common solution is to inject a factory for the testcase in the constructor of your TestSuiteParser class.Vair
B
0

If only one could have a "ServiceLocator" that gets passed around service constructors, but somehow manages to "Declare" the intended dependencies of the class it is being injected into (i.e not hide the dependencies)...that way, all(?) objections to the service locator pattern can be put to rest.

public class MyBusinessClass
{
    public MyBusinessClass(IServiceResolver<Dependency1, Dependency2, Dependency3> locator)
    {
        //keep the resolver for later use
    }
}

Sadly, the above obviously will only ever exist in my dreams, as c# forbids variable generic parameters (still), so manually adding a new generic Interface each time one needs an additional generic parameter, would be unwieldy.

If on the other hand, the above could be achieved despite the limitation of c# in the following way...

public class MyBusinessClass
{
    public MyBusinessClass(IServiceResolver<TArg<Dependency1, TArg<Dependency2, TArg<Dependency3>>> locator)
    {
        //keep the resolver for later use
    }
}

This way, one only needs to do extra typing to achieve the same thing. What i am not sure of yet is if, given the proper design of the TArg class (i assume clever inheritance will be employed to allow for infinite nesting of TArg Generic parameters), DI containers will be able to resolve the IServiceResolver properly. The idea, ultimately, is to simply pass around the very same implementation of the IServiceResolver no matter the generic declaration found in the constructor of class being injected into.

Bren answered 30/11, 2016 at 12:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.