ch04 Minimal API 中的依赖注入
本章主要内容:
- 什么是依赖注入
- 在 Minimal API 项目中使用依赖注入
技术要求
介绍需要安装 .NET 的版本, 以及 Github 仓库中有示例代码.
什么是依赖注入
.NET 原生支持依赖注入, 又称 DI, 是一种软件设计模式.
DI 是控制反转的一种实现. 它是类与其依赖之间的一种设计模式. 而 .NET 中有大量的类都支持依赖注入, 例如日志, 配置等服务.
然后作者介绍了一下传统开发方式与 DI 模式的代码结构的区别.
这里略去细节.
传统需要某个类的实例, 则创建该类的实例, 然后再使用. 这样存在的问题在于:
- 一旦类发生修改, 每个使用的代码都需要再修改.
- 不易于单元测试
依赖注入的优势:
- 使用接口对依赖进行抽象
- 在 .NET 内置服务中注册依赖注入
- 使用构造器进行注入
然后作者对代码进行改良, 按照 DI 的写法来重写. 来说明这个修改很容易. 来说明迁移很简单.
然后使用 Services.AddScoped<>
来演示注册.
依赖注入的生命周期
前面我们介绍了, DI 的优势, 以及如何将之前的代码转换为 DI 的模式.
最后我们将我们的类添加到 .NET 的一个服务集合 (ServiceCollection
) 中. 本节中我们将了解不同的服务的生命周期.
服务的生命周期是指,在容器中, 服务被创建出来后可以使用多久. 一旦注册, 依赖需要一个声明周期.
下面列表中定义了可用的生命周期:
- Transient, 瞬时. 每次需要该实例的时候都会创建一个.
- Scoped, 范围的. 在一个范围内每次使用时创建一个实例, 在同一个 HTTP 请求中会使用一个实例.
- Signleton, 单例. 只在第一次需要实例的时候创建. 下一次使用时会复用该实例.
一般在 Web 开发中, 只会使用到前两种情况. 即 transient 和 scoped. 但是如果有需求, 并不会禁用单例的. 但这不是一个好的设计模式.
在瞬时与范围的模式下, 不使用对象后都会将对象销毁.
在 Minimal API 项目中实现依赖注入
作者直接使用 WebAPI 的模板来修改代码, 用温度计算的方式来演示.
这里了解到为什么说不好单测了.
就是说, 每次使用对象就需要 new 一个出来, 那么每一个 new 出来的对象本质上都不是同一个对象.
理论上说, new 的新对象与原始对象不是一个对象, 无法保证测试出来的结果是复核要求的, 至少需要保证, 在参数不变的情况下实例化出来的对象具有同等特性. 但是使用 DI 可以使用注入来保证是同一个对象.
然后作者展示了改造方法
- 定义接口, 定义接口方法来获得天气数据.
- 然后实现接口. 返回天气数据 (模板代码中使用硬编码, 这里抽象出接口后, 原则上, 数据源可以是任意的).
- 在
Program.cs
中执行builder.Services.AddScoped<接口, 类>()
来完整注册. 即将对象添加到服务集合中了. - 在需要使用的时候, 只需要通过
MapHandler
方法的参数来注入即可 (没有构造器, 直接用方法来注入).
例如:
app.MapGet("/test", (接口 注入的实例) => {...});
有些时候, 你可能需要在启动时的主函数中, 直接使用服务 (没有方法参数注入), 那么可以直接访问 服务集合的实例实现. 例如:
using (var scope = app.Services.CreateScope()) {
var service = scope.ServiceProvider.GetRequiredService<接口>();
...
}