博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ASP.NET Core - 依赖注入
阅读量:5315 次
发布时间:2019-06-14

本文共 4684 字,大约阅读时间需要 15 分钟。

原文:

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

  服务的生命周期  

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

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

  • IServiceCollection               负责注册
  • IServiceProvider                  负责提供实例
  • ActivatorUtilities(暂不讲解)      负责提供实例,允许在依赖关系注入容器中创建没有服务注册的对象。

  服务注册:

  public void ConfigureServices(IServiceCollection services)        {             services.AddTransient
(); services.AddSingleton
(); services.AddScoped
(); ..... }

  通过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
(); services = services.AddScoped
(); services = services.AddSingleton
(); IServiceProvider serviceProvider = services.BuildServiceProvider(); Console.WriteLine(ReferenceEquals(serviceProvider.GetService
(), serviceProvider.GetService
())); Console.WriteLine(ReferenceEquals(serviceProvider.GetService
(), serviceProvider.GetService
())); Console.WriteLine(ReferenceEquals(serviceProvider.GetService
(), serviceProvider.GetService
())); IServiceProvider serviceProvider1 = serviceProvider.CreateScope().ServiceProvider; IServiceProvider serviceProvider2 = serviceProvider.CreateScope().ServiceProvider; Console.WriteLine(ReferenceEquals(serviceProvider1.GetService
(), serviceProvider1.GetService
())); Console.WriteLine(ReferenceEquals(serviceProvider1.GetService
(), serviceProvider2.GetService
())); Console.WriteLine(ReferenceEquals(serviceProvider1.GetService
(), serviceProvider2.GetService
())); /* False * True * True * True * False * True */ }}

 

  对象解析:

    当我们需要从容器中解析一个对象出来的时候,用到了IServiceProvider对象,它根据IServiceCollection注册的服务类型提取相应的服务对象。

public TestController(IServiceProvider serviceProvider){   //如果没有,则返回null   var testService1 = serviceProvider.GetService
(); //如果没有,则抛出InvalidOperationException异常 var testService2 = serviceProvider.GetRequiredService
(); //获取对应的集合 var testService3 = serviceProvider.GetServices
();  var testService4 = serviceProvider.GetRequiredServices
();}  

  

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

    

 

  追本溯源

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

  回到我们的控制台程序,在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
(); _applicationServices = _startup.ConfigureServices(_applicationServiceCollection); EnsureServer(); var builderFactory = _applicationServices.GetRequiredService
(); var builder = builderFactory.CreateBuilder(Server.Features); builder.ApplicationServices = _applicationServices; var startupFilters = _applicationServices.GetService
>(); Action
configure = _startup.Configure; foreach (var filter in startupFilters.Reverse()) { configure = filter.Configure(configure); } configure(builder); this._application = builder.Build(); }

   在这里我们不再深究一个完整的流程的每个阶段,后面源码分析的时候会结合整个流程展示。

posted on
2019-04-24 14:13 阅读(
...) 评论(
...)

转载于:https://www.cnblogs.com/lonelyxmas/p/10762096.html

你可能感兴趣的文章
在16aspx.com上下了一个简单商品房销售系统源码,怎么修改它的默认登录名和密码...
查看>>
linux下Rtree的安装
查看>>
多米诺骨牌
查看>>
Linq 学习(1) Group & Join--网摘
查看>>
asp.net 调用前台JS调用后台,后台掉前台JS
查看>>
苹果手表:大方向和谷歌一样,硬件分道扬镳
查看>>
Android面试收集录15 Android Bitmap压缩策略
查看>>
PHP魔术方法之__call与__callStatic方法
查看>>
ubuntu 安装后的配置
查看>>
【模板】对拍程序
查看>>
【转】redo与undo
查看>>
Django 模型层
查看>>
dedecms讲解-arc.listview.class.php分析,列表页展示
查看>>
安卓当中的线程和每秒刷一次
查看>>
每日一库:Modernizr.js,es5-shim.js,es5-safe.js
查看>>
wpf样式绑定 行为绑定 事件关联 路由事件实例
查看>>
利用maven管理项目之POM文件配置
查看>>
TCL:表格(xls)中写入数据
查看>>
Oracle事务
查看>>
String类中的equals方法总结(转载)
查看>>