获取简单注入器的容器实例

2024-01-21

我正在 ASP.NET MVC 项目中使用简单注入器。我添加了SimpleInjector.Integration.Web.Mvcnuget 包。这增加了SimpleInjectorInitializer上课于App_Start文件夹并初始化 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可以将其注入到任何需要手动执行任何解析的类中。

Update:

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

我知道这在某种程度上是 DI 的反模式,但它在少数地方是必需的,因此注入 DI 容器是下一个最好的事情。简单的注入器示例应该使用静态变量来共享我想避免的容器,顺便说一句,这是不可能的SimpleInjectorInitializer works.


除了属于应用程序启动路径一部分的任何代码之外,任何代码都不应直接依赖于容器(或容器抽象、容器外观等)。这种模式称为服务定位器 http://martinfowler.com/articles/injection.html and 马克·西曼 http://blog.ploeh.dk/ has a 很好的解释 http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/为什么这是一个坏主意。

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

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

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

但请注意,让您的组件需要创建期间的运行时数据是一种代码味道 https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=99。防止这样做。

您可能认为这样做只是将问题转移到工厂实现上。尽管我们将对容器的依赖转移到工厂实现中,但实际上我们正在解决问题,因为工厂实现将成为应用程序的一部分成分根 http://blog.ploeh.dk/2011/07/28/CompositionRoot/,它允许应用程序代码本身忽略任何 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))因此您始终可以将容器注入到任何组件中。这类似于注入IComponentContext使用 Autofac 时。但这同样适用于 Autofac、Simple Injector 和任何其他容器:您不希望将容器注入到位于组合根之外的组件中(而且几乎没有理由这么做)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

获取简单注入器的容器实例 的相关文章

  • 为什么 C# Array.BinarySearch 这么快?

    我已经实施了一个很简单用于在整数数组中查找整数的 C 中的 binarySearch 实现 二分查找 static int binarySearch int arr int i int low 0 high arr Length 1 mid
  • GLKit的GLKMatrix“列专业”如何?

    前提A 当谈论线性存储器中的 列主 矩阵时 列被一个接一个地指定 使得存储器中的前 4 个条目对应于矩阵中的第一列 另一方面 行主 矩阵被理解为依次指定行 以便内存中的前 4 个条目指定矩阵的第一行 A GLKMatrix4看起来像这样 u
  • Web 客户端和 Expect100Continue

    使用 WebClient C NET 时设置 Expect100Continue 的最佳方法是什么 我有下面的代码 我仍然在标题中看到 100 continue 愚蠢的 apache 仍然抱怨 505 错误 string url http
  • 为什么两个不同的 Base64 字符串的转换会返回相等的字节数组?

    我想知道为什么从 base64 字符串转换会为不同的字符串返回相同的字节数组 const string s1 dg const string s2 dq byte a1 Convert FromBase64String s1 byte a2
  • 在结构中使用 typedef 枚举并避免类型混合警告

    我正在使用 C99 我的编译器是 IAR Embedded workbench 但我认为这个问题对于其他一些编译器也有效 我有一个 typedef 枚举 其中包含一些项目 并且我向该新类型的结构添加了一个元素 typedef enum fo
  • 秒表有最长运行时间吗?

    多久可以Stopwatch在 NET 中运行 如果达到该限制 它会回绕到负数还是从 0 重新开始 Stopwatch Elapsed返回一个TimeSpan From MSDN https learn microsoft com en us
  • 为什么当实例化新的游戏对象时,它没有向它们添加标签? [复制]

    这个问题在这里已经有答案了 using System Collections using System Collections Generic using UnityEngine public class Test MonoBehaviou
  • 嵌套接口:将 IDictionary> 转换为 IDictionary>?

    我认为投射一个相当简单IDictionary
  • OleDbDataAdapter 未填充所有行

    嘿 我正在使用 DataAdapter 读取 Excel 文件并用该数据填充数据表 这是我的查询和连接字符串 private string Query SELECT FROM Sheet1 private string ConnectStr
  • 如何从 appsettings.json 文件中的对象数组读取值

    我的 appsettings json 文件 StudentBirthdays Anne 01 11 2000 Peter 29 07 2001 Jane 15 10 2001 John Not Mentioned 我有一个单独的配置类 p
  • 创建链表而不将节点声明为指针

    我已经在谷歌和一些教科书上搜索了很长一段时间 我似乎无法理解为什么在构建链表时 节点需要是指针 例如 如果我有一个节点定义为 typedef struct Node int value struct Node next Node 为什么为了
  • 控件的命名约定[重复]

    这个问题在这里已经有答案了 Microsoft 在其网站上提供了命名指南 here http msdn microsoft com en us library xzf533w0 VS 71 aspx 我还有 框架设计指南 一书 我找不到有关
  • 使用 x509 证书签署 json 文档或字符串

    如何使用 x509 证书签署 json 文档或字符串 public static void fund string filePath C Users VIKAS Desktop Data xml Read the file XmlDocum
  • 如何从两个不同的项目中获取文件夹的相对路径

    我有两个项目和一个共享库 用于从此文件夹加载图像 C MainProject Project1 Images 项目1的文件夹 C MainProject Project1 Files Bin x86 Debug 其中有project1 ex
  • cmake 将标头包含到每个源文件中

    其实我有一个简单的问题 但找不到答案 也许你可以给我指一个副本 所以 问题是 是否可以告诉 cmake 指示编译器在每个源文件的开头自动包含一些头文件 这样就不需要放置 include foo h 了 谢谢 CMake 没有针对此特定用例的
  • 如何将带有 IP 地址的连接字符串放入 web.config 文件中?

    我们当前在 web config 文件中使用以下连接字符串 add name DBConnectionString connectionString Data Source ourServer Initial Catalog ourDB P
  • 基于 OpenCV 边缘的物体检测 C++

    我有一个应用程序 我必须检测场景中某些项目的存在 这些项目可以旋转并稍微缩放 更大或更小 我尝试过使用关键点检测器 但它们不够快且不够准确 因此 我决定首先使用 Canny 或更快的边缘检测算法 检测模板和搜索区域中的边缘 然后匹配边缘以查
  • C# 模拟VolumeMute按下

    我得到以下代码来模拟音量静音按键 DllImport coredll dll SetLastError true static extern void keybd event byte bVk byte bScan int dwFlags
  • 良好的 WiX 编辑器 [重复]

    这个问题在这里已经有答案了 我目前正在开发一个使用 WiX 创建 MSI 的项目 我过去在 Sourceforge 上使用 WiXEdit 来管理包含在 WiX 项目中的文件 因为它比直接操作 XML 稍微容易一些 但它仍然有点笨重 有谁知
  • Windows 和 Linux 上的线程

    我在互联网上看到过在 Windows 上使用 C 制作多线程应用程序的教程 以及在 Linux 上执行相同操作的其他教程 但不能同时用于两者 是否存在即使在 Linux 或 Windows 上编译也能工作的函数 您需要使用一个包含两者的实现

随机推荐