第5课:依赖注入:良好架构的起点
学习分享 丨作者 / 郑 子 铭 丨公众号 / DotNet NB / CloudNative NB
为什么要使用依赖注入框架
借助依赖注入框架,我们可以轻松管理类之间的依赖,帮助我们在构建应用时遵循设计原则,确保代码的可维护性和可扩展性
ASP.NET Core 的整个架构中,依赖注入框架提供了对象创建和生命周期管理的核心能力,各个组件相互协作,也是由依赖注入框架的能力来实现的
组件包
Microsoft.Extensions.DependencyInjection.Abstractions
Microsoft.Extensions.DependencyInjection
依赖注入的核心是以上两个组件包,一个是抽象包,一个是具体的实现
这里用到了一个经典的设计模式,接口实现分离模式
组件只需要依赖抽象接口,而不需要依赖具体实现,当使用的时候注入它的具体实现即可
这样做的好处是可以在使用时决定具体的实现,也就意味着未来可以做任意的扩展,替换依赖注入框架的具体实现
默认情况下,使用 .NET Core 提供的内置依赖注入框架,也可以使用第三方的依赖注入框架来替换默认实现
核心类型
IServiceCollection:服务的注册
ServiceDescriptor:每一个服务注册时的信息
IServiceProvider:具体的容器,由 ServiceCollection Build 产生
IServiceScope:一个容器的子容器的生命周期
生命周期
单例 Singleton:在整个根容器的生命周期内,都是单例,不管是子容器还是根容器,与作用域的区别是:一个是全局的,一个是范围的单例
作用域 Scoped:在 Scope 的生存周期内,也就是容器的生存周期内,或者子容器的生存周期内,如果我的容器释放掉,我的对象也会释放掉
瞬时(暂时)Transient:每一次从容器里面获取对象时,都可以得到一个全新的对象
新建一个 ASP.NET Core Web 应用程序 DependencyInjectionDemo,选择API
添加一个 Services 文件夹,新建三个服务代表三个生命周期的服务
在 Startup 中注册服务
在 Controller 里面获取我们的服务
注释 Get 方法
启动程序,刷新浏览器再次访问接口,输出如下:

单例模式两次的 HashCode 没有变化
两个瞬时服务两次的 HashCode 完全不同,意味着瞬时服务每次请求都会得到一个新对象
范围服务每个请求内是相同的,不同的请求之间得到的对象实例是不同的
除了使用泛型的方式注册服务之外,还有其他的方式
添加一个 OrderService
在 Startup 中注册服务
在服务端 WeatherForecastController 定义另外一个接口
调整一下程序的启动页面,Properties 下的 launchSetting.json 的这一行代码
修改路由
启动程序,输出如下:
只有一个实例,说明 TryAddSingleton 没有生效
接着,注册两个服务
启动程序,输出如下:
结果获取到了两个实例
接下来,了解一下 TryAddEnumerable 与 TryAddSingleton 的区别
注册服务
启动程序,输出如下:
因为已经注册过 OrderService,所以第二句代码不生效
以不同的实现注册服务
启动程序,输出如下:
这样就可以获取到两个服务实例
刷新浏览器,再执行一遍
因为注册的是单例,所以两次请求获取到的实例都是相同的
这样做的好处是:一方面避免一个服务重复注册,也可以控制一个服务需要注册不同的实现
注册完毕之后,想替换某些组件的某些部分时,可以使用 Replace 和 RemoveAll
启动程序,输出如下:
从结果看出,注册的 OrderService1 被替换为 OrderService2
下面介绍 RemoveAll
这种情况下程序会报错,因为所有 IOrderService 的注册被移除
下面介绍如何注册泛型模板
当需要注册一组泛型实现的时候
实际上注册的时候并不知道泛型类的具体类型入参
依赖注入框架为我们提供了泛型模板的注册方式
通过一行代码来注册所有此泛型的具体实现
定义一个泛型接口
泛型模板注册方法
它的生命周期与之前的注册方式是一致的
不过它无法通过泛型 API 注册
需要注册两个 service 的 type
第一个入参是服务的类型
第二个入参是服务实现的类型
接下来,看看如何在 controller 中使用
在 controller 中有两种依赖注入的实例的获取方式:
通过 controller 构造函数注入
通过 [FromServices] 注入
当定义一个 controller 的时候
它的服务是大部分接口都需要使用的情况下
推荐的做法是用构造函数注入的方式
如果这个服务仅仅在某一个接口使用的情况下
推荐使用 [FromServices] 注入
GitHub源码链接:https://github.com/MingsonZheng/DotNetCoreDevelopmentActualCombat/tree/main/DependencyInjectionDemo
Last updated