考慮到主題問題,在這里不打算詳細講解依賴注入的概念,需要了解依賴注入的可以關注我的DI&IoC分類講解,這里我們專注於ASP.NET Core 體系中系統自帶的原生IoC容器是如何讓我們實現注入和解析的。
服務的生命周期
在開始之前,我們先了解一下服務的生命周期,這僅涉及到IServiceCollection和IServiceProvider兩個核心對象,這也是我們開篇文章中闡述的兩個重要對象。
服務注冊:
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<ITransientTest, TransientTest>(); services.AddSingleton<ISingletonTest, SingletonTest>(); services.AddScoped<IScopedTest, ScopedTest>(); ..... }
通過IServiceCollection這個對象,系統將相應的服務以不同的生命周期模式(Transient、Scoped和Singleton)注冊到ServiceCollection對象里面。
在此需要解釋一下服務的生命周期
Singleton:整個應用程序生命周期內只創建一個實例
Transient:每一次請求都會創建一個新的實例
Scoped: 每次從同一個容器中獲取的實例是相同的、
interface ITransientTest { } interface ISingletonTest { } interface IScopedTest { } class TransientTest : ITransientTest { } class SingletonTest : ISingletonTest { } class ScopedTest : IScopedTest { } class Program { static void Main(string[] args) { IServiceCollection services = new ServiceCollection(); services = services.AddTransient<ITransientTest, TransientTest>(); services = services.AddScoped<IScopedTest, ScopedTest>(); services = services.AddSingleton<ISingletonTest, SingletonTest>(); IServiceProvider serviceProvider = services.BuildServiceProvider(); Console.WriteLine(ReferenceEquals(serviceProvider.GetService<ITransientTest>(), serviceProvider.GetService<ITransientTest>())); Console.WriteLine(ReferenceEquals(serviceProvider.GetService<IScopedTest>(), serviceProvider.GetService<IScopedTest>())); Console.WriteLine(ReferenceEquals(serviceProvider.GetService<ISingletonTest>(), serviceProvider.GetService<ISingletonTest>())); IServiceProvider serviceProvider1 = serviceProvider.CreateScope().ServiceProvider; IServiceProvider serviceProvider2 = serviceProvider.CreateScope().ServiceProvider; Console.WriteLine(ReferenceEquals(serviceProvider1.GetService<IScopedTest>(), serviceProvider1.GetService<IScopedTest>())); Console.WriteLine(ReferenceEquals(serviceProvider1.GetService<IScopedTest>(), serviceProvider2.GetService<IScopedTest>())); Console.WriteLine(ReferenceEquals(serviceProvider1.GetService<ISingletonTest>(), serviceProvider2.GetService<ISingletonTest>())); /* False * True * True * True * False * True */ } }
對象解析:
當我們需要從容器中解析一個對象出來的時候,用到了IServiceProvider對象,它根據IServiceCollection注冊的服務類型提取相應的服務對象。
public class Test { private readonly IServiceProvider _serviceProvider;
public Test(IServicCollection serviceCollection) { _serviceProvider = serviceCollection.BuildServiceProvider(); } public TestController() { //如果沒有,則返回null var testService1 = _serviceProvider.GetService<ITestService>(); //如果沒有,則拋出InvalidOperationException異常 var testService2 = _serviceProvider.GetRequiredService<ITestService>(); //獲取對應的集合 var testService3 = _serviceProvider.GetServices<ITestService>(); var testService4 = _serviceProvider.GetRequiredServices<ITestService>(); } }
追本溯源
這是WebHost調用Startup類的Configure方法創建管道的過程
public void Initialize() { _startup = _hostingServiceProvider.GetService<IStartup>(); _applicationServices = _startup.ConfigureServices(_applicationServiceCollection); EnsureServer(); var builderFactory = _applicationServices.GetRequiredService<IApplicationBuilderFactory>(); var builder = builderFactory.CreateBuilder(Server.Features); builder.ApplicationServices = _applicationServices; var startupFilters = _applicationServices.GetService<IEnumerable<IStartupFilter>>(); Action<IApplicationBuilder> configure = _startup.Configure; foreach (var filter in startupFilters.Reverse()) { configure = filter.Configure(configure); } configure(builder); this._application = builder.Build(); }
在這里我們不再深究一個完整的流程的每個階段,后面源碼分析的時候會結合整個流程展示。

