Get the container instance for Simple Injector

前端 未结 1 1828
梦毁少年i
梦毁少年i 2021-02-02 14:59

I am using Simple Injector with a ASP.NET MVC project. I added the SimpleInjector.Integration.Web.Mvc nuget package. This adds SimpleInjectorInitializer

相关标签:
1条回答
  • 2021-02-02 15:53

    Except for any code that is part of the startup path of the application, no code should depend directly on the container (or a container abstraction, container facade, etc). This pattern is called Service Locator and Mark Seemann has a good explanation why this is a bad idea.

    So components (such as Controllers) should not depend on the container directly, since this hides the used dependencies and makes classes harder to test. Furthermore your code starts to depend on an external framework (making it harder to change) or depending on an abstraction it doesn't need to know about.

    My controller uses a service who initialization depends upon the input parameter passed in the controller method and hence the dependency cannot be instantiated during construction time

    There's a general pattern for this problem: the abstract factory design pattern. The factory pattern allows you to delay the creation of types and allows you to pass in extra runtime parameters for the construction of a certain type. When you do this, your controller doesn't have to depend on Container and it prevents you from having to pass in a constructed container in your unit tests (DI frameworks should in general not be used in your unit test projects).

    Do note however that letting your components require runtime data during creation is a code smell. Prevent doing that.

    You might think that by doing this we are just moving the problem to the factory implementation. Although we are moving the dependency on the container into the factory implementation, we are in fact solving the problem because the factory implementation will be part of the application's Composition Root, which allows the application code itself oblivious to any DI framework.

    So this is how I advice you to structure your code:

    // Definition of the factory in the UI or BL layer
    public interface ISomeServiceFactory
    {
        ISomeService Create(int inputParameter);
    }
    
    // Controller depending on that factory:
    public class MyController : Controller
    {
        private readonly ISomeServiceFactory factory;
    
        public MyController(ISomeServiceFactory factory)
        {
            this.factory = factory;
        }
    
        public ActionResult Index(int value)
        {
            // here we use that factory
            var service = this.factory.Create(value);
        }
    }
    

    In your composition root (the start up path) we define the factory implementation and the registration for it:

    private class SomeServiceFactory : ISomeServiceFactory
    {
        private readonly Container container;
    
        // Here we depend on Container, which is fine, since
        // we're inside the composition root. The rest of the
        // application knows nothing about a DI framework.
        public SomeServiceFactory(Container container)
        {
            this.container = container;
        }
    
        public ISomeService Create(int inputParameter)
        {
            // Do what ever we need to do here. For instance:
            if (inputParameter == 0)
                return this.container.GetInstance<Service1>();
            else
                return this.container.GetInstance<Service2>();
        }
    }
    
    public static void Initialize()
    {
        var container = new Container();
    
        container.RegisterSingle<ISomeServiceFactory, SomeServiceFactory>();
    }
    

    Upon creation, the Container registers itself (using the call RegisterSingle<Container>(this)) so you can always inject the container into any component. That's similar to injecting the IComponentContext when working with Autofac. But the same holds for Autofac, Simple Injector, and any other container: you don't want to inject your container into components that are located outside the composition root (and there hardly ever is a reason for it).

    0 讨论(0)
提交回复
热议问题