06 | 作用域與對象釋放行為
作用域主要由 IServiceScope 這個接口來承載
對於實現 IDisposable 類的實例的對象,容器會負責對其生命周期進行管理,使用完畢之后,他會釋放這些對象
實現 IDisposable 接口類型的釋放:
- 1、容器只會負責由其創建的對象,如果這個對象是自己創建出來並放到容器里的,容器不負責釋放這個對象
- 2、在容器和子容器釋放時,容器才會去釋放這些對象,也就是說容器的生命周期與其創建的對象的生命周期是有對應關系的
兩點建議:
- 1、在根容器,最好不要創建實現了 IDisposable 瞬時服務
- 2、避免手動創建實現了 IDisposable 對象,然后塞到容器里面,應該盡可能地使用容器來管理我們對象的創建和釋放
演示代碼:
https://github.com/witskeeper/geektime/tree/master/samples/DependencyInjectionScopeAndDisposableDemo
先看一下服務
namespace DependencyInjectionScopeAndDisposableDemo.Services
{
public interface IOrderService
{
}
public class DisposableOrderService : IOrderService, IDisposable
{
public void Dispose()
{
Console.WriteLine($"DisposableOrderService Disposed:{this.GetHashCode()}");
}
}
}
首先定義 IOrderService
接着定義 IOrderService 的實現 DisposableOrderService,並實現了 IDisposable 這個接口
在釋放的時候打印釋放信息,並輸出對象的 HashCode
接着是服務注冊(Startup)
services.AddTransient<IOrderService,DisposableOrderService>();
這里先注冊一個瞬時服務,將 IOrderService 注冊進去
然后看一下控制器(WeatherForecastController)
[HttpGet]
public int Get([FromServices] IOrderService orderService,
[FromServices] IOrderService orderService2)
{
return 1;
}
這里 FromServices 獲取了兩次 IOrderService
這里不需要寫任何代碼對它進行操作,因為整個生命周期是由容器去管理的
啟動程序,輸出如下:
DisposableOrderService Disposed:10579059
DisposableOrderService Disposed:47945396
可以看出,執行完畢之后,DisposableOrderService 會被釋放掉,並且兩個對象都會被釋放掉
兩個對象的 HashCode 不同
瞬時服務在每一次獲取的時候都會獲得一個新的對象
接着,添加一行代碼表示服務
[HttpGet]
public int Get([FromServices] IOrderService orderService,
[FromServices] IOrderService orderService2)
{
Console.WriteLine("接口請求處理結束");
return 1;
}
輸出一下,表示我們的接口已經訪問完畢,看一下釋放時機在哪里
啟動程序,輸出如下:
接口請求處理結束
DisposableOrderService Disposed:35023218
DisposableOrderService Disposed:13943705
由此看出,接口請求處理結束后,才釋放對象
接下來看一下 Scoped 模式
服務注冊
services.AddScoped<IOrderService>(p => new DisposableOrderService());
控制器
[HttpGet]
public int Get([FromServices] IOrderService orderService,
[FromServices] IOrderService orderService2)
{
Console.WriteLine("=======1==========");
// HttpContext.RequestServices
// 是當前請求的一個根容器
// 應用程序根容器的一個子容器
// 每個請求會創建一個容器
using (IServiceScope scope = HttpContext.RequestServices.CreateScope())
{
// 在這個子容器下面再創建一個子容器來獲取服務
var service = scope.ServiceProvider.GetService<IOrderService>();
}
Console.WriteLine("=======2==========");
Console.WriteLine("接口請求處理結束");
return 1;
}
啟動程序,輸出如下:
=======1==========
DisposableOrderService Disposed:31307802
=======2==========
接口請求處理結束
DisposableOrderService Disposed:31614998
每次請求會獲得兩個釋放,意味着每創建一個 Scoped 的作用域,每個作用域內可以是單例的


本作品采用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。
歡迎轉載、使用、重新發布,但務必保留文章署名 鄭子銘 (包含鏈接: http://www.cnblogs.com/MingsonZheng/ ),不得用於商業目的,基於本文修改后的作品務必以相同的許可發布。
如有任何疑問,請與我聯系 (MingsonZheng@outlook.com) 。

