首页 > 其他分享 >依赖注入 (DI) 是.NET中一个非常重要的软件设计模式,它可以帮助我们更好地管理和组织组件,提高代码的可读性

依赖注入 (DI) 是.NET中一个非常重要的软件设计模式,它可以帮助我们更好地管理和组织组件,提高代码的可读性

时间:2023-05-18 09:01:17浏览次数:47  
标签:依赖 服务 DI 软件设计 ServiceProvider 作用域 实例 Scoped NET

依赖注入 (DI) 是.NET中一个非常重要的软件设计模式,它可以帮助我们更好地管理和组织组件,提高代码的可读性,扩展性和可测试性。在日常工作中,我们一定遇见过这些问题或者疑惑。

  1. Singleton服务为什么不能依赖Scoped服务?
  2. 多个构造函数的选择机制?
  3. 源码是如何识别循环依赖的?

虽然我们可能已经知道了答案,但本文将通过阅读CLR源码的方式来学习DI实现机制,同时也更加深入地理解上述问题。如果您不想阅读源码,可以直接跳至文末的解决方案。

一、源码解读

理论知识

理论篇可以先看一下,防止在下文代码不知道这些对象的作用。如果有些概念不是很清晰可以先记着,带入下文源码,应该就可以理解

ServiceProvider: ServiceProvider(依赖注入容器)不仅对外提供GetService()、GetRequiredService()方法,还可以方便地注册和管理应用程序需要的各种服务。
通过创建ServiceProvider的方式,我们可以更好地理解管理和控制服务实例的生命周期和依赖关系。

  1. 应用程序级别的根级ServiceProvider
    .NET Core应用程序通常会使用一个应用程序级别的根级ServiceProvider,它是全局唯一的,并且负责维护所有单例服务的实例。这个实例通常是由WebHostBuilder、HostBuilder或ServiceCollection等类创建和配置的,可以通过IServiceProvider接口来访问。

  2. 每个请求的作用域级别的ServiceProvider
    除了根级ServiceProvider之外,在.NET Core中还可以创建每个请求的作用域级别的ServiceProvider,它通常用于管理Scoped和Transient服务的生命周期和依赖关系。每个作用域级别的ServiceProvider都有自己独立的作用域,可以通过IServiceScopeFactory创建,同时也继承了根级ServiceProvider中注册的所有单例服务的实例。

  3. 自定义级别的ServiceProvider
    在某些情况下,我们可能需要自定义级别的ServiceProvider来满足特定的业务需求,例如,将多个ServiceProvider组合起来以提供更高级别的服务解析和管理功能。此时,我们可以通过实现IServiceProviderFactory接口和IServiceProviderBuilder接口来创建和配置自定义级别的ServiceProvider,从而实现更灵活、可扩展的依赖注入框架。

生命周期管理: 我们可以将依赖注入容器看作一个树形结构,其中root节点的子节点是Scoped节点,每个Scoped节点的子节点是Transient节点(如果存在)。在容器初始化时,会在root节点下创建和缓存所有单例服务的实例,以及创建第一个Scoped节点。每个Scoped节点下都有一个独立的作用域,用于管理Scoped服务的生命周期和依赖关系,同时还继承了父级节点(即root或其他Scoped节点)的所有单例服务的实例。
在处理每个新的请求时,依赖注入容器会创建一个新的Scoped节点,并在该节点下创建和缓存该请求所需的所有Scoped服务的实例。在完成请求处理后,该Scoped节点及其下属的服务实例也将被销毁,从而确保Scoped服务实例的生命周期与请求的作用域相对应。

重要对象

  • IServiceCollection: 用于注册应用程序所需的服务实例,并将其添加到依赖注入容器中。

  • IServiceScopeFactory: 用于创建依赖注入作用域(IServiceScope)的工厂类。每个IServiceScope都可以独立地管理Scoped和Transient类型的服务实例,并在作用域结束时释放所有资源。IServiceScope通过ServiceProvider属性来访问该作用域内的服务实例

  • ServiceProvider: 可以看作是一个服务容器,它可以方便地注册、提供和管理应用程序需要的各种服务。还支持创建依赖注入作用域(IServiceScope),可以更好地管理和控制服务实例的生命周期和依赖关系

  • IServiceProviderFactory: 创建最终的依赖注入容器(IServiceProvider),提供默认的DefaultServiceProviderFactory(也就是官方自带的IOC),也支持自定义的,比如autofac的AutofacServiceProviderFactory工厂。

  • ServiceProviderEngineScope: 实现了IServiceProvider和IDisposable接口,用于创建和管理依赖注入作用域(Scope)。通过使用ServiceProviderEngineScope,我们可以访问依赖注入作用域中的服务实例,并实现Scoped和Transient类型的服务实例的生命周期管理。作用域机制可以帮助我们更好地管理和控制应用程序的各个组件之间的依赖关系

  • CallSiteFactory: 通常由依赖注入容器(如ServiceProvider)在服务解析过程中使用。当容器需要解析某个服务时,它会创建一个CallSiteFactory对象,并使用其中的静态方法来创建对应的ServiceCallSite对象。然后,容器会将这些ServiceCallSite对象组合成一个树形结构,最终构建出整个服务实例的解析树。

  • ServiceCallSite: 表示服务的解析过程。它包含了服务类型、服务的生命周期、以及从容器中获取服务实例的方法等信息

  • CallSiteVisitor: 通常由依赖注入容器(如ServiceProvider)在服务解析过程中使用。当容器需要解析某个服务时,它会创建一个ServiceCallSite的对象图,并将其传递给CallSiteVisitor进行遍历和访问。CallSiteVisitor通过调用不同节点的虚拟方法,将每个节点的信息收集起来,并最终构建出服务实例的解析树。

  • CallSiteValidator 通常由依赖注入容器(如ServiceProvider)在服务解析过程中使用,用于验证ServiceCallSite对象图的正确性。它提供了一组检查方法,可以检测ServiceCallSite对象图中可能存在的循环依赖、未注册的服务类型和生命周期问题等

标签:依赖,服务,DI,软件设计,ServiceProvider,作用域,实例,Scoped,NET
From: https://www.cnblogs.com/mabenlei/p/17410863.html

相关文章

  • element 时间日期选择器el-date-picker点击清空按钮报错:TypeError: Cannot read prope
       参考:http://www.taodudu.cc/news/show-805096.html?action=onClick......
  • 原来.NET写的Linux桌面这么好看?
    如何使用Blazor在Linux平台下运行Desktop程序本文将讲解如何使用Blazor运行跨平台应用,应用到的技术有以下几点BlazorMasaBlazorPhotino.BlazorUbuntu用于验证跨平台性,并且是否提高开发效率,Blazor和Photino一块使用的技术称为BlazorHybrid,Blazor的优点Blazor是一种使用......
  • 【愚公系列】2023年05月 .NET CORE工具案例-对象映射Master的使用
    (文章目录)前言对象映射框架Master可以帮助开发人员将对象映射到数据库,以进行数据持久化。它还可以支持ORM(对象关系映射),以及其他数据库技术,比如存储过程。它可以帮助开发人员更快、更有效地完成数据库操作。Master官网:https://github.com/MapsterMapper/Mapster一、对象映射m......
  • Visual Studio Code 小白使用介绍
    前言现在使用Vscode编码的人越来越多,凭借着免费,开源,轻量,跨平台的特点收货了一大批忠实粉丝最近因项目需要开始使用Vscode,但不知为何,感觉有点力不从心,不知道该怎么用首先想到去官网看看,然后放弃了(英语渣渣表示压力山大,其实正因为英语差,才更应该锻炼一下的,大家不要学我23333)最后自己......
  • Codeforces Round 868 (Div. 2) A-D
    CodeforcesRound868(Div.2) A.A-characteristicintfac[N];map<int,int>mp;voidinit(){fac[1]=0;mp[0]=1;for(inti=2;i<N;i++){fac[i]=fac[i-1]+(i-1);mp[fac[i]]=i;}}voidsolve(){intn=read(),k=rea......
  • ERROR: No matching distribution found for paddlepaddle问题的解决
    问题描述按照教程输入相关代码语句,然后一直出现这个错误问题解决发现是自己的Python版本不太对,32bit的python并没有对应的Paddlepaddle源,需要改换成64bit源的才行!......
  • 解决Net Framework2.0无法安装
    无需更新widows,听说你不能更新?什么?你也不行?一、那先试试这个可以么?感觉不太行,此处省略~二、不可以就用这个验证系统盘下是否存在文件夹C:\Windows\winsxs以管理员运行CMDdism.exe/online/enable-feature/featurename:NetFX3/Source:C:\Windows\winsxsOK......
  • 29、利用 LNMP 实现phpMyAdmin并利用redis会话保持,用页面管理数据库
    建设第二个网站,利用LNMP实现实现phpMyAdmin并利用redis会话保持,用页面管理数据库在100web1、200web2上创建网站数据存放目录[root@ubunt~]#mkdir/data/php2进入官网https://www.phpmyadmin.net/下载[root@ubuntphp2]#wgethttps://files.phpmyadmin.net/phpMyAdmin/5.......
  • ASP.NET Core Swagger接入使用IdentityServer4 的 WebApi
    写在前面是这样的,我们现在接口使用了Ocelot做网关,Ocelot里面集成了基于IdentityServer4的开发的授权中心用于对Api资源的保护。问题来了,我们的Api用了SwaggerUI做接口的自文档,那就蛋疼了,你接入了IdentityServer4的Api,用SwaggerUI调试、调用接口的话,妥妥的401,未授权啊。那有小伙伴就......
  • 第四周编程作业(一)-Building your Deep Neural Network: Step by Step
    BuildingyourDeepNeuralNetwork:StepbyStepWelcometoyourweek4assignment(part1of2)!Youhavepreviouslytraineda2-layerNeuralNetwork(withasinglehiddenlayer).Thisweek,youwillbuildadeepneuralnetwork,withasmanylayersasyou......