考虑到主题问题,在这里不打算详细讲解依赖注入的概念,需要了解依赖注入的可以关注我的DI&IoC分类讲解,这里我们专注于ASP.NET Core
体系中系统自带的原生IoC容器是如何让我们实现注入和解析的。

  服务的生命周期  

  在开始之前,我们先了解一下服务的生命周期,这仅涉及到IServiceCollection和IServiceProvider
两个核心对象,这也是我们开篇文章中阐述的两个重要对象。

  在.NET Core中DI的核心分为两个组件:IServiceCollection和 IServiceProvider。

* IServiceCollection               负责注册
* IServiceProvider                  负责提供实例
* ActivatorUtilities(暂不讲解)      负责提供实例,允许在依赖关系注入容器中创建没有服务注册的对象。
  服务注册:
  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(IServiceProvider serviceProvider) { _serviceProvider =
serviceProvider; }   public TestController()   {   //如果没有,则返回null   var
testService1 = _serviceProvider.GetService<ITestService>();   //
如果没有,则抛出InvalidOperationException异常   var testService2 =
_serviceProvider.GetRequiredService<ITestService>();   //获取对应的集合   var
testService3 = _serviceProvider.GetServices<ITestService>();     var
testService4 = _serviceProvider.GetRequiredServices<ITestService>();   }  }
 

  整体的一个依赖注入流程如下图

    

 

  追本溯源

  在上面我们知道了如何通过IServiceCollection和IServiceProvider这两个对象
注册和解析对象,那么问题来了,这两个对象是什么时候和如何创建的呢?

  回到我们ASP.NET Core - 从Program和Startup开始
<https://www.cnblogs.com/lex-wu/p/10693437.html>
的控制台程序,在WebHostBuilder调用Build方法创建
WebHost的过程中,这时会创建一个ServiceCollection对象,并将系统需要的一系列预定义服务(如
IHostingEnvironment、IConfiguration、IHttpContextFactory、IStartupFilter等
)注册在它之上。接下来会利用这个ServiceCollection对象创建出对应的ServieProvider(BuildServiceProvider()),而这两个ServiceProvider和ServiceCollection对象会一并传递给最终创建的WebHost,WebHost会利用这个ServiceProvider对象解析出Startup对象,并调用它的Configure方法用来完成对整个管道的建立。


  非常值得一提的是,Startup中的ConfigureServices方法是允许具有一个IServiceProvider类型的返回值,如果这个方法返回一个具体的ServiceProrivder,那么WebHostBuilder将不会利用ServiceCollection来创建新的ServiceProvider,而是直接使用这个返回的ServiceProvider来传递到Startup的Configure方法以供使用。我们后面会基于这个特性使用其他的IoC框架进行扩展替换。

   这是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(); }
   在这里我们不再深究一个完整的流程的每个阶段,后面源码分析的时候会结合整个流程展示。

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信