Singleton(单例)
创建服务类的单个实例,将其存储在内存中,并在整个应用程序中重复使用。我们可以将 Singleton 用于实例化成本昂贵的服务。可以使用 AddSingleton 方法注册 Singleton 服务,如下所示:
```
services.AddSingleton<IProductService, ProductService>();
```
Scoped(范围内)
每个请求会创建一次服务实例。参与处理单个请求的所有中间件、MVC 控制器等等,都将获得相同的实例。实体框架上下文(Entity Framework context)是使用 Scoped 服务的一个很好的场景。我们可以使用 AddScoped 方法注册 Scoped 服务,如下所示:
```
services.AddScoped<IProductService, ProductService>();
```
Transient(临时)
每次请求 Transient 生命周期服务时都会创建它们。此生命周期最适合轻量级、无状态的服务。我们可以使用 AddTransient 方法注册 Transient 服务,如下所示:
```
services.AddTransient<IProductService, ProductService>();
```
Singleton
单例模式。IServiceProvider作为DI容器,单例模式的服务需要由根容器销毁。它的生命周期会随根容器的销毁而销毁,也就是说,应用程序停掉了它才会销毁。
Scope
Scope实际上是由一个IServiceScope接口来描述的,上面有写,它是由ServiceProvider的一个扩展方法CreateScope来实现的,内部由IserviceScopeFacrory来最终生成一个Scope,这个Scope生成的时候会创建一个新的ServiceProvider,利用新生成的ServiceProvider来提供的服务也就形成了一个Scope的概念。顺便插一句,任何一个ServiceProvider都有一个根容器的引用,所有的Provider都引用了同一个根容器。它的生命周期随创建它的Scope的销毁而销毁,在http://asp.net core里面,当客户端发起请求时,都会新创建一个Scope,然后都是利用这个新创建的Scope中的ServiceProvider属性来提供服务的。
Transient
随用随取,用完就销毁。它的生命周期通Scope,都是随创建它的ServiceProvider的销毁而销毁。
Scope的特殊说明
在ASP.NETCore应用中,将某个服务注册的生命周期设置为Scoped的真正意图是希望依赖注入容器根据接收的每个请求来创建和释放服务实例,但是一旦出现上述这种情况,就意味着Scoped服务实例将变成一个Singleton服务实例,这样的Scoped服务实例直到应用关闭才会被释放,这无疑不是我们希望得到的结果。如果某个Scoped服务实例引用的资源(如数据库连接)需要被及时释放,这可能会造成难以估量的后果。为了避免这种情况的出现,在利用IServiceProvider对象提供服务的过程中可以开启针对服务范围的验证。
一般情况下,生命周期较长的服务不应该依赖一个生命周期较短的服务,BuildServiceProvider方法可以传入一个bool类型的参数,这个参数解决了这么一个问题:
举个例子,比方说在http://asp.net core项目中我们使用entity framework core,要添加一个DbContext,这个DbContext是被添加成Scope生命周期的,也就是说它会随着http请求的发起创建,请求结束后消亡。但是如果他被一个Singleton的服务所依赖/引用,那么它的生命周期就会变成Singleton。这个连接永远都不会释放,当许多请求过来的时候,数据库的连接池的连接就会变得不够用。这本身是一种错误的实践,避免这样的错误就是在BuilServiceProvider这个方法中传入一个true的bool值,指示DI在注入服务的时候要判断Scope的服务是否被错误的使用,一般来说错误的使用有两种情况:
第一种情况是用根ServiceProvider来创建一个Scope的服务。在根容器上面创建的服务会由根容器来负责销毁,那么也就是说,Scope的服务也就变成了Singleton的了。因为根容器只有在应用程序停止运行的时候才会销毁。
第二种情况是Scope的服务被Singleton的服务依赖/引用。那么这个Scope的服务也会随依赖它的Singleton服务变成Singleton的。
扩展点
.NETCore具有一个承载(Hosting)系统,该系统承载需要在后台长时间运行的服务,一个http://ASP.NET Core应用仅仅是该系统承载的一种服务(IHostedService)而已。承载系统总是采用依赖注入的方式消费它在服务承载过程中所需的服务。对于承载系统来说,原始的服务注册总是体现为一个IServiceCollection集合,最终的依赖注入容器则体现为一个IServiceProvider对象,如果要将第三方依赖注入框架整合进来,就需要利用它们解决从IServiceCollection集合到IServiceProvider对象的适配问题。
具体来说,我们可以在IServiceCollection集合和IServiceProvider对象之间设置一个针对某个第三方依赖注入框架的ContainerBuilder对象:先利用包含原始服务注册的IServiceCollection集合创建一个ContainerBuilder对象,再利用该对象构建作为依赖注入容器的IServiceProvider对象。
-
Transient 类型的服务在每次注入或请求的时候被创建。
-
Scoped 类型的服务按照作用域被创建。在Web程序中,每个Web请求都会创建新的隔离的服务作用域。这意味着Scoped类型的服务通常会根据Web请求创建。
Singleton 类型的服务由DI容器创建。这通常意味着它们根据应用程序仅仅被创建一次,然后用于应用程序的整个生命周期。