【问题标题】:Dependency Injection into Class Libraries that are chained together?依赖注入到链接在一起的类库中?
【发布时间】:2018-07-13 12:36:08
【问题描述】:

我很难弄清楚这应该如何工作。这是针对 .NET Core 应用程序的。

我有一个定义 ICryptoService 的加密库和一个实现类 DefaultCryptoService,我还有一个 CryptoSettings 类,我在启动时从 appsettings.json 填充。所以:

public class DefaultCryptoService : ICryptoService {
    private CryptoSettings cryptoSettings;
    public DefaultCryptoService(CryptoSettings settings){
        cryptoSettings = settings;
    }
}

在我的启动中:

services.AddSingleton<ICryptoProvider>(new DefaultCryptoProvider(cryptoSettings));

到目前为止一切顺利。但是现在想象一下,我在另一个类库中有一个数据层,它需要利用这些加密功能并连接到数据库。它基本上是实现基本 IRepository 模式的存储库类。我的控制器将根据需要调用 IRepository 实现以使用数据库,但是该层如何访问我在 Startup 中初始化的 ICryptoProvider 实现?

HomeController --> UserRepository --> 需要访问 DatabaseSettings(从配置,就像我的加密一样),以及我在启动时设置的 ICryptoProvider 的实现,以便它可以根据需要加密/解密用户信息。

我觉得我正处于将所有这些放在一起的风口浪尖,但我不了解将它们链接在一起的正确方法。

【问题讨论】:

  • how does that layer get access to the ICryptoProvider implementation that I initialized in Startup? 通过将ICryptoProvider 作为构造函数依赖。您对 IoC 容器(以及哪些容器)有多少经验?
  • @mjwills 所以你的意思是我所有的存储库现在都必须定义同时采用 DatabaseSettings 和 CryptoSettings 的构造函数?好吧,我想,但是如果你有很多依赖项,这不是很丑吗?我可以看到需要访问各种不同库的数据层
  • OK I guess, but doesn't this get really ugly if you have many dependencies? 你建议什么替代方案?它必须以某种方式获得它的依赖关系。另一种选择是服务定位器 - 这更糟。

标签: c# .net dependency-injection .net-core


【解决方案1】:

您只需注册您的类型并提供定义需求的公共构造函数,如果这些可用,魔法就会发生。带你加密提供商,你可以用不同的方式注册它:

services.AddSingleton(cryptoSettings);
services.AddSingleton<ICryptoProvider, DefaultCryptoProvider>();

这样写就解决了。实际上,您不必在代码中的任何位置直接调用构造函数,它将通过依赖解析为您完成。

还要检查服务收集的不同方法 - 并非所有类都应该是单例的。


class UserRepository : IUserRepository{
    UserRepository(IDatabaseContext context, ICryptoProvider provider){
    }
}

并注册:

services.AddTransient<IUserRepository, UserRepository>();

您还需要添加数据库上下文才能解析此存储库。 这可以是非常深的结构,您可以想象控制器不直接与存储库一起工作,但有一些服务层:

class UserService : IUserService{
    UserService(IUserRepository userReposiotry, IMembershipRepository membershipRepository){
    }
}

和控制器构造函数是这样的:

    UserController(IUserService service){
    }

从控制器的角度来看,您并不关心需要两个存储库,而每个存储库都需要数据库上下文和加密提供程序。控制器只需要验证有效负载,如果有效,则将作业委托给服务进行处理。反过来,服务不关心存储库的内部逻辑和需求。

至于注册,它是对services 集合AddTransient&lt;Interface,Class&gt;() 的一系列调用。是的,您将在接口和类之间获得 1:1 的关系。这对于单元测试来说是一件好事。

【讨论】:

  • 对不起,我没听懂你的意思,控制器如何在不实例化的情况下获取它需要的存储库的引用?是您在启动时注册它并让控制器的构造函数为 repo 获取参数吗?公共类 MyController(IRepository repo) ?
  • 是的 - 几乎 IRepository 是通用的,因为会有很多存储库,您需要一些已注册且足够具体的内容,以便 IUserRepository。确定需要创建什么的繁重工作由 DI 实现为您完成。
  • @Rafal 好的,所以我明白了,假设它是一个 UserController ......你能分享一下它的构造函数是什么样的吗? Startup 中的注册是什么样的,所以我是 100 % 确定我这样做是正确的,谢谢!
  • @snappymcsnap 我已经修改了答案。
猜你喜欢
  • 2021-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-11
  • 2023-02-20
  • 1970-01-01
相关资源
最近更新 更多