【问题标题】:Resolving dependencies automatically in .NET Core 2.2在 .NET Core 2.2 中自动解决依赖关系
【发布时间】:2019-05-21 20:39:39
【问题描述】:

.NET Core 2.2 中的内置依赖注入框架是否在创建实例时自动解析依赖并注入实例?或者注入依赖的唯一方法是在创建新实例时显式解决它?

我正在构建一个类库项目(因此,[FromServices] 属性对我来说不是一个选项),在我看来,我几乎必须在每个类的构造函数中传递 IServiceProvider。

我是不是误会了什么?

注意:代码 sn-p 只是说明性的。

public class A
{
    public A()
    {

    }

    public void DoSomethingWithB()
    {
        var b = new B(// To resolve IConfiguration here, I need IServiceProvider. That means I will need to inject IServiceProvider in class A first. Will it go on nesting like this everywhere?);
    }
}

public class B
{
    private IConfiguration _config;
    public B(IConfiguration config)
    {
        _config = config;
    }
    public void DoWork()
    {
        // Use _config here.
    }
}

【问题讨论】:

  • 如果你正在构建一个类库,那么类库的使用者负责在构造函数中传入它需要的对象。那可能是DI框架。请注意,良好实践建议B 不依赖于IConfiguration,而是一个允许消费者提供正确值的接口,方法是将其实例传递给A 的构造函数
  • 也许您不需要手动创建B 并在A 构造函数中简单地接受B 对象?您正在尝试使用Service Locator pattern,这确实是一种反模式。
  • @DavidG:是的,但正如我所见,IServiceProvider 会出现在太多地方。 .NET Core DI 本身给我一个实例怎么样,因为明确说明了依赖关系并且 DI 映射是在启动时构建的?还是 .NET Core 不支持这种模式?
  • 为什么到处都需要IServiceProvider?让 DI 通过向 DI 框架注册 A 来创建您的实例,同时注册 B
  • @YuriiN。是不是被微软强制使用服务定位器?

标签: asp.net-core dependency-injection .net-core


【解决方案1】:

你的类库项目根本不应该知道任何依赖注入。你应该做的是确保每个类都接受它在构造函数中的所有依赖项,如下所示:

public void MyClass(IMyDependency dependency)

它适用于名为Composition Root 的东西,以确保一切都从顶部得到解决。例如。对于 ASP.NET,框架本身将调用 Resolve 以获取 Controller 并组成整个对象树,您的类将直接或间接依赖于控制器。

这个原则有个花哨的名字叫“好莱坞原则”:不要叫我们,我们叫你。如果您自己解决依赖关系(即“调用它们”),那么您正在做一些调用 Service Locator 的事情,这被认为是一种反模式。因此,相反,您依赖某人(即“他们给您打电话”)将在某个初始入口点在您的类中注入正确的依赖项。

此外,任何知道 DI 容器的类库设计都会在将来导致许多问题,例如进行单元测试,更改 DI 容器等。所以最好的办法是对那里的容器一无所知。

附:当微软将很多库与 DI 容器 (IServiceCollection) 捆绑在一起时,微软本身在我眼中实际上犯了一个错误。例如。日志库、HTTP 工厂等都依赖这个 DI 容器来完成这项工作,几乎不可能切换到另一个容器。

我知道这将使人们在不太了解 DI 的情况下更容易使用它,但从长远来看,它确实会限制你并使例如单元测试比较麻烦。

【讨论】:

    【解决方案2】:

    您应该在ConfigureServices 方法中的服务提供者中注册服务B。然后您可以使用常规构造函数注入将服务B 注入服务A。例如:

    public void ConfigureService(IServiceCollection services)
    {
        services.AddSingleton<B>();
    
        // Other stuff..
    }
    
    public class A
    {
        private readonly B _b;
    
        public A(B b)
        {
            _b = b;
        }
    
        // Use service B in your methods...
    }
    
    public class B
    {
        private IConfiguration _config;
    
        public B(IConfiguration config)
        {
            _config = config;
        }
    }
    

    您可以根据需要创建更深的嵌套级别。例如,您也可以将服务A 添加到依赖容器中(使用services.AddSingleton&lt;A&gt;()),然后将服务A(将自动注入服务B 等)注入另一个服务或控制器.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-04-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多