接著 前面,前面的過程是普遍常用的依賴註入解析過程,我們正常都是在startup類中註入依賴服務,但是,筆者這周開發的時候遇到個問題,不同服務的生命周期不同,不能調用服務。舉個例子,AddDbContext註入資料庫上下文,生命周期預設是scoped,但是我有個需求註入的服務是單例的,因此我註入的單 ...
接著 前面,前面的過程是普遍常用的依賴註入解析過程,我們正常都是在startup類中註入依賴服務,但是,筆者這周開發的時候遇到個問題,不同服務的生命周期不同,不能調用服務。舉個例子,AddDbContext註入資料庫上下文,生命周期預設是scoped,但是我有個需求註入的服務是單例的,因此我註入的單利服務不能引用資料庫上下文來調用資料庫,最後是通過CreateScoped來解決的。因此,這篇文章說到說到CreateScoped。
public static IServiceScope CreateScope(this IServiceProvider provider) { return provider.GetRequiredService<IServiceScopeFactory>().CreateScope(); }View Code
最終是由獲取介面IServiceScopeFactory的服務(也就是介面的實現類),由服務調用其CreateScope方法,作為返回值。
GetRequiredService方法的最終實現:
public static object GetRequiredService(this IServiceProvider provider, Type serviceType) { provider.GetService(serviceType); }View Code
由介面IServiceProvider的實現類來獲取指定的服務。
IServiceProvider介面,有三個實現類:
ServiceProviderEngineScope
ServiceProviderEngine
ServiceProvider
查看源碼可知,而這三個類最終都是調用IServiceProviderEngine介面的GetService方法。該介面的實現類有多個如下:
DynamicServiceProviderEngine
RuntimeServiceProviderEngine
ILEmitServiceProviderEngine
ExpressionsServiceProviderEngine
CompiledServiceProviderEngine
ServiceProviderEngine
前五個類都是直接繼承自類ServiceProviderEngine,同時這五個類的實現都是通過特定的方式來實例化指定介面,也就是返回一個介面的服務對象。
ServiceProviderEngine類的實現簽名:
internal abstract class ServiceProviderEngine : IServiceProviderEngine, IServiceScopeFactory {}View Code
也就是說最後所有的實現都是基於IServiceProviderEngine以及IServiceScopeFactory介面。
internal interface IServiceProviderEngine : IDisposable, IServiceProvider { IServiceScope RootScope { get; } } public interface IServiceScopeFactory { IServiceScope CreateScope(); }View Code
IServiceScope介面的定義:
public interface IServiceScope : IDisposable { IServiceProvider ServiceProvider { get; } }View Code
這趟下來,就獲取了介面IServiceScopeFactory的服務。隨後就通過服務調用CreateScope方法。上面說了繼承自介面IServiceScopeFactory的類有五個,最後都是繼承自ServiceProviderEngine,這裡調用CreateScope方法,最後也是調用ServiceProviderEngine類的CreateScope方法。簽名如下:
public IServiceScope CreateScope() { if (_disposed) { ThrowHelper.ThrowObjectDisposedException(); } return new ServiceProviderEngineScope(this); }View Code
返回一個介面IServiceScope的實例化類。該方法簽名如下:
internal class ServiceProviderEngineScope : IServiceScope, IServiceProvider { }View Code
最後我們還是調用ServiceProviderEngine類實例來調用GetService方法獲取指定介面的服務。
舉個實例使用的代碼示例:
using (var _scope = _serviceProvider.CreateScope()) { var _context = _scope.ServiceProvider.GetService<PracticeDevDbContext>(); }
也就是說,是用CreateScope方法來解析介面獲取服務,並不是直接的調用ServiceProvider來獲取介面的服務,而是通過類外的IServiceScope來
解析指定的介面獲取服務,轉了個彎。
那麼為什麼要這麼實現呢?其實我並不清楚,只是遇到了一個依賴註入的問題,最後是通過如上代碼解析上下文類獲取數據的。後續有待研究。