文章目录
一、根容器和子容器
1.根容器
根容器是由通过ServiceCollection Build出的容器。
2.子容器
子容器是由容器创建出来的,有如下两种方式来创建。
第一:RequestService是指ASP.NET Core框架为每个HTTP请求创建的子容器,就是当前请求的容器。
代码如下(示例):
using (IServiceScope serviceScope = HttpContext.RequestServices.CreateScope())
{
var service = serviceScope.ServiceProvider.GetService<IClientService>();
Debug.WriteLine($"service 's hashcode={service.GetHashCode()}");
var service1 = serviceScope.ServiceProvider.GetService<IClientService>();
Debug.WriteLine($"service1 's hashcode={service1.GetHashCode()}");
}
第二:使用IServiceprovider的扩展方法CreateScope也可以来创建子容器。
二、实现 IDisposable 接口类型的释放
1.DI 只负责释放由其创建的对象实例
普通方式比如:
services.AddSingleton<IClientService, ClientService>();
工厂注册方式比如:
var service = new ClientService();
services.AddSingleton<IClientService>(serviceProvider =>
{
return service;
});
代码如下(示例):
单例:
/// <summary>
/// 单例模式,就一个对象,每次都是得到的同一个对象,不会释放;只有程序关闭的时候才会释放
/// </summary>
/// <param name="clientService1"></param>
/// <param name="clientService2"></param>
/// <returns></returns>
public int GetSingleServiceLifetime([FromServices] IClientService clientService1, [FromServices] IClientService clientService2)
{
using (IServiceScope serviceScope = HttpContext.RequestServices.CreateScope())
{
var service = serviceScope.ServiceProvider.GetService<IClientService>();
var service1 = serviceScope.ServiceProvider.GetService<IClientService>();
}
Debug.WriteLine("Done");
return 0;
}
Transient:
/// <summary>
/// 每次都是一个不同的对象,会释放
/// </summary>
/// <param name="clientService1"></param>
/// <param name="clientService2"></param>
/// <returns></returns>
public int GetTransientServiceLifetime([FromServices] IClientService clientService1, [FromServices] IClientService clientService2)
{
using (IServiceScope serviceScope = HttpContext.RequestServices.CreateScope())
{
var service = serviceScope.ServiceProvider.GetService<IClientService>();
var service1 = serviceScope.ServiceProvider.GetService<IClientService>();
}
Debug.WriteLine("Done");
return 0;
}
Result如下:

Scope:
/// <summary>
/// 每个作用域内只能获取相同的对象,作用域释放的时候,再释放对象
/// </summary>
/// <param name="clientService1"></param>
/// <param name="clientService2"></param>
/// <returns></returns>
public int GetScopeServiceLifetime([FromServices] IClientService clientService1, [FromServices] IClientService clientService2)
{
using (IServiceScope serviceScope = HttpContext.RequestServices.CreateScope())
{
var service = serviceScope.ServiceProvider.GetService<IClientService>();
var service1 = serviceScope.ServiceProvider.GetService<IClientService>();
}
Debug.WriteLine("Done");
return 0;
}

2.DI 不负责释放不是由其创建的对象实例
比如注册方式:
services.AddSingleton<IClientService>(new ClientService());
代码如下(示例):
public int GetServiceLifetime([FromServices]IClientService clientService, [FromServices]IHostApplicationLifetime hostApplicationLifetime,[FromQuery]bool stop =false)
{
using (IServiceScope serviceScope = HttpContext.RequestServices.CreateScope())
{
var service = serviceScope.ServiceProvider.GetService<IClientService>();
Debug.WriteLine($"service 's hashcode={service.GetHashCode()}");
var service1 = serviceScope.ServiceProvider.GetService<IClientService>();
Debug.WriteLine($"service1 's hashcode={service1.GetHashCode()}");
}
if (stop)
{
hostApplicationLifetime.StopApplication();
}
Debug.WriteLine($"clientService 's hashcode={clientService.GetHashCode()}");
Debug.WriteLine("Done");
return 0;
}
只有当stop=true,程序关闭的时候才会释放的。
三、建议
1.避免在根容器获取实现了 IDisposable 接口的瞬时服务
代码如下(示例):
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//从根容器获取瞬时服务,容器不会自动释放,若需要释放只能手动
//var s1 = app.ApplicationServices.GetService<IClientService>();
//ClientService s2 = (ClientService)app.ApplicationServices.GetService<IClientService>();
//s2.Dispose();
//var s3 = app.ApplicationServices.GetService<IClientService>();//在跟容器获取作用域服务会直接报错
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
}
2.避免手动创建实现了 IDisposable 对象,应该使用容器来管理其生命周期
四、源码下载
总结
- AddSingleton支持手动new一个对象注入到容器,这种方式只有程序关闭的时候才去释放,其他两种方式都不支持new一个对象注入容器。
- db一般是scope,因为它用完需要释放还给连接池,容器可以帮你释放,service、repository也是scope,因为它们依赖db;单例模式仅在明确需要全局共享一个实例时使用
- 容器只会管理实现了IDisposable的服务的释放(调用Dispose方法),对于未实现IDisposable的服务,容器是不管的。另外对象最终的回收,是由GC完成的。生命周期的定义,是决定了容器是返回一个新对象,还是复用之前创建的对象。
- IServiceCollection表示定义的服务类型、构造方式和生命周期的配置表,IServiceprovider则表示根容器,当调用GetService时,它会根据IServiceCollection中的定义来决定如何构造(或者返回一个已有的)服务对象。
- 单例模式,则程序退出时释放;作用域模式,则每个作用域结束时释放,也就是每个请求结束时。

本文探讨了依赖注入中根容器和子容器的概念,重点解释了DI如何处理实现了IDisposable接口的对象实例释放,强调DI只负责由其创建的实例。建议避免在根容器中获取瞬时服务,并推荐使用容器管理对象生命周期。同时,文章提到了ASP.NET Core中的RequestService和CreateScope创建子容器的方式。总结指出,单例模式在程序关闭时释放,作用域模式在请求结束时释放,而容器只管理实现了IDisposable的服务释放。
1600

被折叠的 条评论
为什么被折叠?



