AspNetCore中的依赖注入详解

news2024/11/24 14:41:33

1 概述

ASP.NET Core在启动以及后续针对每个请求的处理过程中的各个环节都需要相应的组件提供相应的服务,为了方便对这些组件进行定制, ASP.NET Core通过定义接口的方式对它们进行了“标准化”,我们将这些标准化的组件称为服务, ASP.NET Core在内部专门维护了一个IOC容器来提供所需的服务。服务的创建到销毁的过程完全交给IOC容器,大大降低了耦合度。

在这里插入图片描述

依赖注入旨在实现针对服务对象的动态提供。具体来说,服务的消费者利用一个独立的容器(Container)来获取所需的服务对象,容器自身在提供服务对象的过程中会自动完成依赖的解析与注入。话句话说,由DI容器提供的这个服务对象是一个” 开箱即用”的对象,这个对象自身直接或者间接依赖的对象已经在初始化的工程中被自动注入其中了。框架负责创建依赖关系的实例,并在不再需要时将其释放。

核心组件说明

依赖注入有两个核心组件:IServiceCollectionIServiceProvider
在这里插入图片描述

   public void ConfigureServices(IServiceCollection services){
   }

    public interface IServiceCollection : IList<ServiceDescriptor>, ICollection<ServiceDescriptor>, IEnumerable<ServiceDescriptor>, IEnumerable
    {
    }

IServiceCollection,是一个实现了IList的服务描述类,负责注册实例,即服务类型【接口】与服务实现。这个组件在startup中的ConfigureServices方法的参数中

IServiceProvider 简单的内置容器,通过IServiceCollection的拓展方法BuildServiceProvider()创建,意即根据服务描述信息来管理服务组件的整个生命周期。消费者在消费服务组件时,就可以轻松地从容器中根据已经注册的服务描述信息获得服务实例。

    public void ConfigureServices(IServiceCollection services)
        {
            //IServiceCollection ICollection<ServiceDescriptor>的服务描述实现类,一系列方法注册服务的描述信息,包括服务类型、对应的服务实例、服务的生命周期等
            //AddSingleton<TService, TImplementation> TService 服务类型,一般是接口形式,TImplementation 具体的实现类型。一个服务类型可对应多个服务实现类型。
            services.AddSingleton<IUser, User>();


            services.AddSingleton<IComputerBrand, HuaWeiComputer>()
                    .AddSingleton<IComputerBrand, LenovoComputer>();

          

            //服务类型IUser,具体实现通过自定义类注册。
            services.AddSingleton<IUser>(x => new User
            {
                Name = "lyf"
            });

            Console.WriteLine("IOC  registered {0} services definition ", services.Count());

            //拓展方法 注册MVC组件
            services.AddMvc(options => options.EnableEndpointRouting = false);

            //返回ServiceProvider 是AspNetCore内置的IOC容器,默认是通过IServiceCollection创建,读取已注册的服务描述信息,创建服务实例
            var ioc = services.BuildServiceProvider();


            //从容器中获得注册的服务信息
            IEnumerable<IComputerBrand> brands = ioc.GetServices<IComputerBrand>();
            Console.WriteLine("IOC  registered {0} type of computer brand", brands.Count());


            var computer = ioc.GetRequiredService<IComputerBrand>();
            Console.WriteLine("Computerbrand:{0}", computer.ToString());


            ioc.GetService<IUser>();

        }

AspNetCore默认使用这个容器去管理服务,所以忽略这个BuildServiceProvider()方法。因此在这个ConfigServices方法中,更主要的是去关注服务的注册,如何去绑定服务类型与实例的关系。

服务注册方法

常用的注册方式是AddSington、AddScope、AddTranisent,分别在容器中注册单例的、暂时、瞬时的服务。以注册单例服务AddSington说明【常用方法】。其他的服务注册用法是类似的。

 // TService 服务类型,一般是接口形式,TImplementation 具体的实现类型。一个服务类型可对应多个服务实现类型。
AddSingleton<TService, [DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes.PublicConstructors)] TImplementation>(this IServiceCollection services)
            where TService : class
            where TImplementation : class, TService;


//TService 服务类型,一般是接口形式 ,通过回调工厂去创建实现类
AddSingleton<TService>(this IServiceCollection services, Func<IServiceProvider, TService> implementationFactory) where TService : class;

构造器函数注入

在实际消费者在消费服务组件时,并不会不直接使用从容器中GetService的方法去获得服务。这样子会暴露容器中所有注册的组件信息,并且需要先取得IOC 容器对象,这个步骤不非必要的。
构造器注入【项目中最常见的使用方法,暂不支持方法注入与属性注入的方法】,在构造函数中借助参数将依赖的对象注入到创建的对象之中。通过调用构造函数的方式来创建服务实例时,传入构造函数的所有参数必须先被初始化。存在多个构造函数数时,将会选择所有参数被实例化,而且参数值是最多的一个构造函数。如果未找到指定的构造函数,那么服务无法获得,服务抛出异常。

   [Route("/api/[controller]/[action]")]
    public class ComputerController:ControllerBase
    {
        private IEnumerable<IComputerBrand> brands;
        /// <summary>
        /// 构造器函数注入,可以给类中的brands对象通过构造器传递参数并赋值
        /// </summary>
        /// <param name="brands"></param>
        public ComputerController(IEnumerable<IComputerBrand> brands) {
            //赋值后,对象不为空
            this.brands = brands;
        }
        public void ShowBrand() {
            foreach (IComputerBrand computer in brands) {
                Console.WriteLine(computer.ToString()+"\n");
            }
        }
    }

除了加入自定义的服务之外,显然不够我们处理HTTP请求以及其他的业务功能,在项目初始化后将会注入默认的服务。在Program中通过默认配置创建服务器时,会注册一些默认的服务。这些服务和我们自行注册的服务并没有任何区别,只要我们知道对应的服务类型,就可以通过构造器函数注入的方式获取并使用它们。

  • ILoggerFactory
  • ILogger<>
  • IApplicationBuilderFactory
  • IHttpContextFactory
  • IOptions<>
  • IStartupFilter
  • Istartup
  • IHostingEnvironment

如果我们需要这些预注册的服务,我们可以通过构造函数注入的方式来使用它们。

AutoFac替换内置的IOC容器

ASP.NET Core内置的IOC容器默认的实现对于一些小型的项目完全够用,对于大型项目而言,对象的依赖关系复杂,内置的IOC容器难以管理对象的创建于对象的生命周期。原因在于只提供了最基本的AddXXXX方法来注册服务实例,因此项目中将会出现很多这样的代码。为了简化此步骤,可使用第三方IOC容器替换内置的IOC容器,如Autofac。

步骤一:下载Autofac的Nuget包,这里netcore 3.1下载的是autofac8.00的版本,可自行下载对应的版本。
步骤二: Program类中修改默认注入方式,采用Autofac
步骤二: 新增服务注册类,多种方法注册服务描述信息
步骤四:修改配置类StartUp,增加ConfigureContainer方法,
将注册在AutoFac的服务描述实例化到容器中。

替换内置的IOC容器,采用autofac


        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                //Autofac替换默认的IOC容器
                .UseServiceProviderFactory(new AutofacServiceProviderFactory())
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });

新增服务注册类

    public class AutoFacModule : Module
    {
        /// <summary>
        /// AutoFac注册类
        /// </summary>
        /// <param name="builder"></param>
        protected override void Load(ContainerBuilder builder)
        {
           // ContainerBuilder  是一个可以将IServiceCollection 服务描述类转化为容器的中间类
           //使用ContainerBuilder 加入服务注册信息
            builder.RegisterType<HuaWeiComputer>().As<IComputerBrand>();
            builder.RegisterType<LenovoComputer>().As<IComputerBrand>();

        }
    }

修改startUp


        //autofac 新增
        public ILifetimeScope AutofacContainer { get; private set; }

        //autofac 新增
        public void ConfigureContainer(ContainerBuilder builder)
        {
            // 直接用Autofac注册我们自定义的 
            builder.RegisterModule(new AutoFacModule());
        }

netcore 3.X版本与2.X 整合AutoFac框架存在些许差异,后者在注册服务时是直接返回一个可以替换原生IOC容器IServiceProvider。而不是void 无返回,采用内置的IOC容器
public IServiceProviderConfigureServices(IServiceCollection services){
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/588228.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【高数+复变函数】Laplace变换

文章目录 【高数复变函数】Laplace变换1. 问题引入及定义2. 存在定理3. 常见Laplace变换 【高数复变函数】Laplace变换 1. 问题引入及定义 上一节&#xff1a;【高数复变函数】傅里叶积分 回顾之前我们讲的傅里叶变换要满足的条件有&#xff08;也就是傅里叶积分要满足的条件…

RL - 强化学习 Decaying Epsilon Greedy 算法解决多臂老虎机问题

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://blog.csdn.net/caroline_wendy/article/details/130945234 Decaying Epsilon Greedy 算法是一种强化学习中的探索策略&#xff0c;可以平衡开发和探索之间的矛盾。基本思想是&#xff0…

第15章:索引的数据结构

一、为什么使用索引 1.索引是存储引擎用于快速找到记录的一种数据结构。相当于一本书的目录。在进行数据查找时&#xff0c;首先查看查询条件是否命中某条索引&#xff0c;符合则通过索引查找相关数据。如果不符合则需要全表扫描&#xff0c;一条一条查找记录&#xff0c;直到…

Layui源码解读之define函数

一、layui.define 用法 layui.define([mods], callback) 通过layui.define该方法可在新的 JS 文件中定义一个 layui 模块。 mods 是可选的&#xff0c;用于声明该模块所依赖的模块。callback 为模块加载完毕的回调函数&#xff0c;它返回一个 exports 参数&#xff0c;用于输出…

鸿蒙App开发选择Java还是JavaScript?

众所周知&#xff0c; Java和 JavaScript是两种编程语言&#xff0c;这两种语言在不同的环境中都有许多用途。在鸿蒙 App开发中&#xff0c; Java和 JavaScript是两种常见的编程语言&#xff0c;它们都具有广泛的应用&#xff0c;并且都有其独特的优势。下面我们将就这两种编程…

LiveGBS国标GB/T28181国标平台功能-电子地图移动位置订阅mobileposition地图定位GPS轨迹坐标位置获取redis获取位置

LiveGBS国标GB/T28181国标平台功能-电子地图移动位置订阅mobileposition地图定位GPS轨迹坐标位置获取redis获取位置 1、位置订阅1.1、国标设备编辑1.2、选择设备开启位置订阅1.3、全局开启位置订阅1.4、通过目录订阅获取位置(少数情况) 2、经纬度信息查询2.1、访问接口获取2.1.…

详解iPaaS与RPA的区别及各自的应用场景

随着企业数字化转型的加速&#xff0c;业务系统集成和自动化流程成为关键议题。本文旨在探讨iPaaS&#xff08;Integration Platform as a Service&#xff09;与RPA&#xff08;Robotic Process Automation&#xff09;在业务系统集成方面的区别&#xff0c;它们各自的用途和适…

python数据分析案例——零售商店电子销售订单分析

一、项目背景 通过"扫描"零售商店电子销售点个别产品的条形码而获得的消费品销售的详细数据。 这些数据提供了有关所售商品的数量、特征和价值以及价格的详细信息。 二、数据来源 https://www.kaggle.com/marian447/retail-store-sales-transactions 三、提出问…

windows11@OpenWith@选择文件打开方式导致卡死@windows11任务栏显示秒

文章目录 OpenWith选择文件打开方式导致卡死解决方案 windows11任务栏显示秒显示秒的注册表设置取消显示秒: OpenWith选择文件打开方式导致卡死 关键在于一个名为openwith的进程出现问题该进程有时会卡死,并且无法关闭,这个bug存在很久了,具体参考:Windows11 - Microsoft Comm…

MySQL 多行函数

文章目录 多行函数1. 求 country 表中&#xff0c;所有国家人口的平均值&#xff0c;其 SQL 语句实现如下&#xff1a;2. 求 country 表中&#xff0c;所有国家人口的总数&#xff0c;其 SQL 语句实现如下&#xff1a;3. 求 country 表中&#xff0c;人口最多和最少国家的人口数…

KD7742耐压接地泄漏绝缘四合一并行测试仪

一、产品简介 KD7742耐压接地泄漏绝缘四合一并行测试仪具有交/直流耐压、绝缘电阻等项目的测试分析功能&#xff0c;能显示电压、电流和电阻的波形图以及趋势图&#xff0c;以便更直观的监测分析绝缘性能和绝缘崩溃时的各项指标&#xff0c;适用于高要求的测试分析场合。 产品具…

Pig项目新加权限类型生成Token并且解决验证问题

前言 这个教程可能不是最好的,也许是最直白的,你只需要找到对应的地方跟着博主一起去修改就能操作成功,今天用添加 mini 的授权模式的例子说一下这个 mini 模式是自己自定义的,你想叫什么都行 最近可烦死了快被折磨死人,在昨天睡了一觉,今天就解决问题了…睡一觉就能解决问题,那…

教你一步步使用实现TensorFlow 进行对象检测

在本文中,我们将学习如何使用 TensorFlow Hub 预训练模型执行对象检测。TensorFlow Hub 是一个库和平台,旨在共享、发现和重用预训练的机器学习模型。TensorFlow Hub 的主要目标是简化重用现有模型的过程,从而促进协作、减少冗余工作并加速机器学习的研发。用户可以搜索社区…

【数据结构与算法分析inC-MarkAllen】2-算法分析

文章目录 第二章——算法分析2.1 算法评价的量化理论2.1.1 函数渐进增长四种渐进增长定义运算法则两个函数相对增长率判断 2.1.2 算法分析的计算机模型2.1.3 要分析的目标最坏情况 2.1.4 一般法则for循环嵌套for循环顺序语句分支语句二分函数调用 2.2 计算方法2.2.1 循环主体中…

Android应用的加固与逆向

文章目录 前言名词释义加固手段逆向dex文件resources.arscReact Native TODO文档链接工具参考加固工具逆向工具 前言 加固与逆向是安卓攻防的两个方面。搞安卓研发时间长了就不可避免走到这一步。既要研究别人的实现&#xff0c;又要保护好自己的东西。个人认为&#xff0c;逆…

糖尿病首创新药的中国梦

《多肽链》原创出品 作者&#xff5c;慕白 在中国上市一款first-in-class&#xff08;FIC&#xff09;全球首创新药&#xff0c;有多难&#xff1f;先来看一组数据对比。 按照美国FDA的药品评价和研究中心&#xff08;CDER&#xff09;报告数据&#xff0c;2022年有37款新药…

chatgpt赋能python:介绍Python中二次函数的基本知识

介绍Python中二次函数的基本知识 在Python中&#xff0c;二次函数是一个重要的概念&#xff0c;它是由一个二次项、一次项和一个常数项构成的一个代数式。二次函数在数学和物理学中都有广泛的应用&#xff0c;了解二次函数的基本知识对于学习和理解这些领域都是非常重要的。在…

uni-app实现 app 小程序 手机端H5扫码功能

首先 扫码这个功能小程序和App都是有现成的方法 但是H5是不行的 我们可以看这样一段代码 <template><view><!-- #ifdef MP-WEIXIN --><button click"scan">扫描</button><view v-if"result">{{result}}</view>…

长尾词挖掘,挖掘百度相关词和下拉词的操作步骤

什么是下拉词 在搜索引擎的搜索框输入一个关键词的时候&#xff0c;搜索框会推荐一些与这个关键词有关联的长尾关键词&#xff0c;如“汉服”。 什么是相关词 在搜索引擎的搜索框输入一个关键词的时候&#xff0c;一般会推荐与这个关键词相关的长尾关键词。如“汉服”。 挖…

【SpringBoot系列】SpringBoot中 @Configuration 和 @Component 的区别及原理分析

示例 //Component Configuration public class AppConfig {Beanpublic Foo foo() {System.out.println("foo() invoked...");Foo foo new Foo();System.out.println("foo() 方法的 foo hashcode: " foo.hashCode());return foo;}Beanpublic Eoo eoo() {…