一、原理和注意事项:
作用域由 IServiceScope 对象承载,对于实现了IDisposable接口类型的对象,容器会去负责对其生命周期的管理,当使用完毕它会去释放对象;实现IDisposable接口类型对象的释放特点:
- DI 只负责释放由其创建的对象;
- DI 在容器或子容器释放时,释放由其创建的对象实例;
如果对象是由我们自己创建并放到容器里面,容器不负责释放该对象;容器的生命周期与其创建的对象的生命周期有对应关系,这里我们需要以下两点注意事项:
- 在根容器不要去创建实现了 IDisposable 的瞬时服务;
- 避免手动创建对象且将该对象放入容器里面,应该尽可能的使用容器去管理我们的对象的创建和释放;
二、代码示例与测试结果:
首先创建一个 OrderService 的服务,代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace DependencyInjectionScopeAndDisposableDemo.Services
{
public interface IOrderService
{
}
public class DisposableOrderService : IOrderService, IDisposable
{
public void Dispose()
{
Console.WriteLine($"DisposableOrderService Disposed:{this.GetHashCode()}");
}
}
}
然后在 Startup 的 ConfigureServices 中分别注册以下服务,测试作用域对象的生命周期和释放,如下所示:
//1.瞬态
services.AddTransient<IOrderService, DisposableOrderService>();
services.AddTransient<IOrderService>(service => new DisposableOrderService()); //工厂模式注册;
//2.单例
services.AddSingleton<IOrderService, DisposableOrderService>();
services.AddSingleton<IOrderService>(services => new DisposableOrderService());
//3.作用域
services.AddScoped<IOrderService, DisposableOrderService>();
services.AddScoped<IOrderService>(services => new DisposableOrderService());
//4.自创建方式单例注册
var service = new DisposableOrderService();
services.AddSingleton<IOrderService>(service);
测试输出对象的HashCode和该对象的生命周期和释放行为,控制器方法如下:
- 瞬态服务注册测试:
[HttpGet]
public int Get(
[FromServices]IOrderService orderService,
[FromServices]IOrderService orderService2)
{
Console.WriteLine("接口请求处理结束");
return 1;
}
1.瞬态测试输出结果如下:
接口请求处理结束
DisposableOrderService Disposed:21621962
DisposableOrderService Disposed:29422698
瞬时服务在每一接口调用时都会获得一个对象,且在接口处理完毕后将其注册对象服务释放;
- 单例服务注册测试:
2.单例测试,控制器中的请求方法不变(如下3),测试结果如下:
=======1==========
=======2==========
接口请求处理结束
执行顺序一样,但单例模式注册服务的对象不会被释放;
- 作用域服务注册测试:
[HttpGet]
public int Get(
[FromServices]IOrderService orderService,
[FromServices]IOrderService orderService2)
{
#region 测试作用域Scope
Console.WriteLine("=======1==========");
using (IServiceScope scope = HttpContext.RequestServices.CreateScope())
{
//创建作用域子容器
var service = scope.ServiceProvider.GetService<IOrderService>();
var service2 = scope.ServiceProvider.GetService<IOrderService>();
}
Console.WriteLine("=======2==========");
#endregion
Console.WriteLine("接口请求处理结束");
return 1;
}
3.作用域测试输出结果如下:
=======1==========
DisposableOrderService Disposed:8140213
=======2==========
接口请求处理结束
DisposableOrderService Disposed:21353980
同样作用域服务注册还是先执行接口方法,执行完毕再将其对象释放,但同一个作用域内对象只会创建一次(局部单例模式);
- 自创建方式单例注册
4.测试结果如下:
=======1==========
=======2==========
接口请求处理结束
同样的测试结果,自创建注册方式,对象不会被其容器所释放;
以上就是对服务注册的几种方式以及对象释放的生命周期测试结果;