类库中的依赖注入?

问题描述 投票:0回答:1

我尝试寻找简单的解决方案来将依赖项注入到类库中。

我尝试用一个简单的解决方案来解决这个问题,看起来效果很好。

这就是我所做的。

  1. 创建全局静态类(在单独的类库中):
    namespace CompositionRoot
    {    
        public static class Dependencies
        {
            public static IServiceProvider? ServiceProvider = null;   
        }
    
    }
  1. 创建一个服务并将其添加到 IServiceCollection(来自 Main)。
    IServiceCollection services = new ServiceCollection();
    IScriptRepository scriptRepository = new ScriptRepository(
        sensorDataConnectionString, "scripts", ControllerName, _logger);
    services.AddSingleton(scriptRepository);
  1. 创建一个 IServiceProvider 并将其添加到 CompositionRoot(来自 Main):
    IServiceProvider serviceProvider = services.BuildServiceProvider();
    CompositionRoot.Dependencies.ServiceProvider = serviceProvider;
  1. “注入”服务对象(在另一个类库中)
    private readonly IScriptRepository _scriptRepository;

    public BuildingController()
    {
        _scriptRepository= CompositionRoot.Dependencies.ServiceProvider!.GetService<IScriptRepository>()!;
    }

我一直读到这可能是一种“反模式”,但我不确定到底为什么。

这种方法有哪些潜在问题?

c# dependency-injection
1个回答
0
投票

使用静态字段使

IServiceProvider
可以全局访问,就像您在第一个代码示例中所做的那样,是服务定位器反模式的实现。通常不鼓励这样做,本文中解释了这样做的原因。

除了该文章中给出的论点之外,对于 MS.DI,问题变得非常明显,因为从根服务提供者进行解析会导致各种令人讨厌的错误,例如强制依赖项和内存泄漏,尤其是在以下应用程序中:基于请求。换句话说,对于您(或代表您的框架)创建

IServiceScope
范围的应用程序。一般来说,对于 MS.DI,服务应该从一个范围解析 - 而不是根容器,但是静态
ServiceProvider
字段不容易允许代码从正确的“范围”服务提供者解析。

从应用依赖注入模式和实践的角度来看,在应用程序的启动路径(您的 Main)中注册库的组件是明智的做法。这个 Main is 你的Composition Root。组合根是应用程序中的“集中”位置,其中注册了所有依赖项并组合了所有对象图。您不想将此逻辑分散在整个应用程序中,也不想让库或项目本身控制此注册和组合。再说一遍,组合根是该去的地方。 请注意,在这种情况下,“集中”并不意味着“所有人都可以访问”,而是“分组在一起”。由于组合根应该位于应用程序的启动项目中,因此组合根之外的任何代码都不应访问它。组合根内部的代码依赖于应用程序中的

所有内容

,而组合根之外之外的所有内容(这将是应用程序的 99%)都不会注意到组合根的存在。 重要提示:

虽然您在示例中使用术语

CompositionRoot,但该示例显示了与组合根模式相反的情况。在您的示例中,Dependencies

类是共享的——所有人都可以访问——并且,正如我上面指出的,它充当服务定位器。
如果您想更深入地了解 DI 及其模式(例如组合根)及其反模式(例如服务定位器),请首先浏览
本文

,即该文章底部的链接。那篇文章和其他两篇参考文献摘自我的书《依赖注入原理、实践和模式》,显然,该书包含的信息比仅在文章中提供的信息要多得多,更不用说 StackOverflow 的答案了。

此处可免费获取本书的第一章。

© www.soinside.com 2019 - 2024. All rights reserved.