.Net Core DI 服務生命週期
- Scoped:每次Post/Get Request在Application結束前,都會使用相同的instance
- Transient:每次注入都會建立新的instance
- Singleton:應用程式從開始到結束,使用的都是同一個instance。(ex:執行應用程式後,會先進入Program,接著執行Post/Get Request,接著再執行一次Post/Get Request。這種情況使用的都是同一個Service實體。第二次Post/Get Request不會再進入Program,不算Application結束)。
- 模擬測試情境如下:
TestController.cs
IExcelService excelService,
MainService mainService
/*建構子先注入兩個Service*/
public TestController(IExcelService _excelService, MainService _mainService)
{
_excelService = excelService;
_mainService = mainService;
}
[HttpPost]
public async Task<Result<string>> DataCheck([FromBody] ReqGetDiffList data)
{
var hashCode = _excelService.GetHashCode(); //get HashCode
var excelData = await _excelService.ReadExcel("TEST_PATH", null); //_excelService.ReadExcel()會先讀取Excel並把回傳值給_mainService.ProcessExcelData做資料處理。
try
{
var eqmStock = await _mainService.ProcessExcelData(data.FilterFileType, null, null, _optEmployeeIdSettings, "TEST_PATH", excelData);
}
catch (Exception)
{}
......省略......
}
MainService.cs
/*建構子注入IExcelService的實體*/
public MainService(IExcelService _excelService)
{
_excelService = excelService;
}
public async Task<Result<string>> ProcessExcelData(DataTable excelData)
{
var hashCode = _excelService.GetHashCode(); //get HashCode
......省略......
}
由上面程式碼可以看到ExcelService分別於兩個class被注入。
- Scoped測試如下
先用AddScoped註冊Service對應

在TestController.cs底下的_excelService的HashCode為[28137373]

在MainService.cs底下的_excelService的HashCode為[28137373]

如果再重新呼叫一次DataCheck(重新發送一個新的Request),TestController.cs底下的_excelService的HashCode為就又會更新成[30544512]了

由於是同一個Request,所以MainService.cs底下的_excelService.HashCode則會跟TestController下的_excelService.HashCode一樣為[30544512]

從上面測試可以看出來,在同個應用程式Runtime之下,即使IExcelService在分別被TestController跟MainService被注入。但在相同的Request下,所取得的HashCode的值還是一樣,也表示_excelService用的是同一個instance。
- Transient測試如下
先用AddTransient註冊Service對應

在TestController.cs底下的_excelService的HashCode為[26096572]

在MainService.cs底下的_excelService的HashCode為[63555393]

從上面測試可以看出來,在同個應用程式Runtime以及同個Request之下,由於IExcelService在分別被TestController跟MainService被注入。所以取得的HashCode的值會不一樣,也表示_excelService在TestController跟MainService用的是不同instance。但反過來說,如果MainService還有其他地方也要用到_excelService的話,那就會是一樣的instance,因為是從同一個建構子注入的。
- Singleton測試如下
先用AddSingleton註冊Service對應
在TestController.cs底下的_excelService的HashCode為[66500315]

在MainService.cs底下的_excelService的HashCode為[66500315]

重新發送一個新的Request,在TestController.cs底下的_excelService的HashCode還是一樣為[66500315]

重新發送一個新的Request,在MainService.cs底下的_excelService的HashCode還是一樣為[66500315]

由上面的測試可以看到Singleton就比較單純了,不管Request的發送次數或是由注入次數,只要是同一個Runtime之下,都是使用同一個instance。
另外要注意的是,如果高階模組的服務生命週期為Singleton,那麼被注入的模組的服務生命週期就不能為Scoped,否則式會報錯的。以上面的例子來看MainService(高階模組)注入了ExcelService(低階模組),那麼如果MainService的服務生命週期為Singleton,ExcelService的服務生命週期就不能為Scoped。


Ref:
1.【Asp.Net Core】生命週期
2. How to Implement Dependency Injection in C# [Dependency Injection Tutorial]
3. [Day04] 依賴注入 (Dependency Injection) - 我與 ASP.NET Core 3 的 30天