Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 获取Simple Injector的容器实例_C#_Asp.net Mvc_Dependency Injection_Simple Injector - Fatal编程技术网

C# 获取Simple Injector的容器实例

C# 获取Simple Injector的容器实例,c#,asp.net-mvc,dependency-injection,simple-injector,C#,Asp.net Mvc,Dependency Injection,Simple Injector,我在ASP.NETMVC项目中使用SimpleInjector。我添加了SimpleInjector.Integration.Web.Mvcnuget包。这将在App\u Start文件夹中添加SimpleInjectorInitializer类,并初始化DI。代码看起来像 publicstaticvoidinitialize() { //您知道容器可以诊断您的配置吗? //转到:https://simpleinjector.org/diagnostics var container=新容器()

我在ASP.NETMVC项目中使用SimpleInjector。我添加了
SimpleInjector.Integration.Web.Mvc
nuget包。这将在
App\u Start
文件夹中添加
SimpleInjectorInitializer
类,并初始化DI。代码看起来像

publicstaticvoidinitialize()
{
//您知道容器可以诊断您的配置吗?
//转到:https://simpleinjector.org/diagnostics
var container=新容器();
//容器配置代码
DependencyResolver.SetResolver(
新的SimpleInjectorDependencyResolver(容器));
}
这将正确配置MVC控制器的DI

我的问题是,如果我想在任何controller\class中获取容器的实例以手动解决某些依赖关系,我如何才能做到这一点

我之前在AutoFac上工作过,它有一个依赖接口
IComponentContext
,可以将它注入到需要手动执行任何解析的任何类中

更新

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


我知道这在某种程度上是DI的一种反模式,但在少数地方它是必需的,因此注入DI容器是次好的事情。简单注入器示例应该使用静态变量来共享我想要避免的容器,而且通过
SimpleInjectorInitializer
的工作方式也是不可能的。

除了作为应用程序启动路径一部分的任何代码外,任何代码都不应该直接依赖于容器(或容器抽象、容器外观等)此模式被调用,并有一个“为什么这是一个坏主意”的解释

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

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

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

但是请注意,让您的组件需要。防止这样做

您可能会认为,通过这样做,我们只是将问题转移到工厂实现中。虽然我们将容器的依赖性转移到工厂实现中,但实际上我们正在解决问题,因为工厂实现将是应用程序的一部分,这允许应用程序代码本身不受ny 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>();
}
私有类SomeServiceFactory:ISomeServiceFactory
{
专用只读容器;
//这里我们依赖于容器,这很好,因为
//我们在构图根中,其余部分
//应用程序对DI框架一无所知。
公共服务工厂(容器)
{
this.container=容器;
}
公共服务创建(int inputParameter)
{
//做我们在这里需要做的事情。例如:
如果(inputParameter==0)
返回此.container.GetInstance();
其他的
返回此.container.GetInstance();
}
}
公共静态void Initialize()
{
var container=新容器();
container.RegisterSingle();
}

创建时,
容器
会注册自身(使用调用
RegisterSingle(this)
)因此,您始终可以将容器注入任何组件。这类似于在使用Autofac时注入
IComponentContext
。但Autofac、Simple Injector和任何其他容器也是如此:您不希望将容器注入位于合成根目录之外的组件(几乎没有理由这样做).

您可以注入容器,但不应该。在这种情况下,您滥用容器作为一个。为什么您需要在该控制器中使用容器?添加了一个需要支持的场景Hanks Steve,是的,我理解这一部分,并应用了与您在此处解释的相同的模式。但由于工厂本身需要容器,我使用AutoFac
IComponentContext
。我不知道如何在SimpleInjector中执行同样的操作。除了Steven的出色回答之外,我们还可以轻松地使用泛型返回
ISomeService
(而不是使用if/else硬编码)的具体实现,方法是使用以下命令:
public T Create(),其中T:ISomeService{return(T)this.container.GetInstance(typeof(T));}
。然后使用:
var service=this.factory.Create();
。您还需要使用以下命令更新
ISomeServiceFactory
接口:
T Create()其中T:ISomeService;
。我可以看出,理论上为您的代码正在创建的所有类型创建工厂接口是一个好主意。但实际上,可能有一些代码需要创建许多不同类型的对象。然后,您可以使用一个可以实际为您创建许多不同类型的接口。一些基本原理利斯