获取Simple Injector的容器实例

本文关键字:实例 Simple Injector 获取 | 更新日期: 2023-09-27 18:25:09

我正在将Simple Injector与ASP.NET MVC项目一起使用。我添加了SimpleInjector.Integration.Web.Mvc nuget包。这将在App_Start文件夹中添加SimpleInjectorInitializer类并初始化DI。代码看起来有点像

public static void Initialize()
{
    // Did you know the container can diagnose your configuration? 
    // Go to: https://simpleinjector.org/diagnostics
    var container = new Container();
    //Container configuration code
    DependencyResolver.SetResolver(
        new SimpleInjectorDependencyResolver(container));
}

这将正确配置MVC控制器的DI。

我的问题是,如果我想在任何控制器''类中获得容器的实例,以手动解决一些依赖关系,我该怎么做?

我以前研究过AutoFac,它有一个依赖接口IComponentContext,可以注入到任何需要手动进行任何解析的类中。

更新

这是一个场景。我的控制器使用一个服务,该服务的初始化取决于控制器方法中传递的输入参数,因此在构建期间无法实例化依赖关系。

我知道这在某种程度上是DI的反模式,但它在一些地方是必需的,因此注入DI容器是下一个最好的事情。Simple Injector示例应该使用静态变量来共享容器,这是我想要避免的,而且根据SimpleInjectorInitializer的工作方式,这是不可能的。

获取Simple Injector的容器实例

除了作为应用程序启动路径一部分的任何代码外,任何代码都不应直接依赖于容器(或容器抽象、容器外观等)。这种模式被称为服务定位器,Mark Seemann很好地解释了为什么这是一个坏主意。

因此,组件(如控制器)不应该直接依赖于容器,因为这会隐藏所使用的依赖项,并使类更难测试。此外,您的代码开始依赖于外部框架(使其更难更改)或依赖于不需要了解的抽象。

我的控制器使用一个服务,该服务的初始化取决于输入控制器方法中传递的参数,以及依赖关系在施工期间无法实例化

这个问题有一个通用模式:抽象工厂设计模式。工厂模式允许您延迟类型的创建,并允许您为特定类型的构造传递额外的运行时参数。当你这样做时,你的控制器不必依赖Container,它可以防止你在单元测试中传递一个构建的容器(DI框架通常不应该在单元测试项目中使用)。

但是,请注意,在创建过程中让组件需要运行时数据是一种代码气味。防止这样做。

您可能会认为,这样做只是将问题转移到工厂实现上。尽管我们正在将对容器的依赖转移到工厂实现中,但事实上我们正在解决这个问题,因为工厂实现将是应用程序的Composition Root的一部分,它允许应用程序代码本身忽略任何DI框架。

这就是我建议您构建代码的方式:

// 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);
    }
}

在您的组合根(启动路径)中,我们定义了工厂实现及其注册:

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>();
}

创建后,Container会注册自己(使用调用RegisterSingle<Container>(this)),因此您可以始终将容器注入到任何组件中。这类似于在使用Autofac时注入IComponentContext。但Autofac、Simple Injector和任何其他容器也是如此:您不想将容器注入位于组合根之外的组件中(这几乎没有任何原因)。