.NET Core 依赖注入 Microsoft.Extensions.DependencyInjection

2023-12-11 22:21

本文主要是介绍.NET Core 依赖注入 Microsoft.Extensions.DependencyInjection,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 前言
  • 什么是依赖注入
  • C# 使用依赖注入
    • 框架介绍
  • Microsoft.Extensions.DependencyInjection
    • Nuget安装
    • 简单单例使用
      • 打印结果
    • 自动装配
      • 举例
      • 自动装配测试用例
      • 打印结果
      • 自动装配执行顺序
        • 测试用例
        • 有歧义构造函数
        • 渐进式构造函数
        • 循环依赖
      • 自动装配结论
    • 手动装配
      • 手动注入
      • 别名注入
    • 依赖注入的构造顺序
  • 结尾

前言

依赖注入是一个非常重要的编程思想,就和面向过程和面向对象一样,IOC和控制反转是一种解耦的编程思想。

什么是依赖注入

[C#]理解和入门依赖注入

为什么要用IOC:inversion of controll反转控制(把创建对象的权利交给框架)

C# 使用依赖注入

框架介绍

目前.NET 有两个最优的依赖注入框架

  • Microsoft.Extensions.DependencyInjection:微软官方依赖注入框架,听说在.net core 8.0得到了最强的性能提升
  • Autofac:听说也是最强的依赖注入框架,性能强,开销低,功能完善。

Dependency injection in ASP.NET Core

Autofac 官网

深入浅出依赖注入容器——Autofac

Microsoft.Extensions.DependencyInjection

目前打算用微软的IOC,毕竟是官方背书,性能有保证。

C# 依赖注入IServiceCollection的AddSingleton方法使用

Nuget安装

在这里插入图片描述

简单单例使用

声明个测试类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace NETCore8.Models
{public class Person{public int Id { get; set; }public string ?Name { get; set; }public int Age { get; set; }}
}

主函数代码

using Microsoft.Extensions.DependencyInjection;
using NETCore8.Models;
using Newtonsoft.Json;
using System.ComponentModel.Design;namespace NETCore8
{internal class Program{static void Main(string[] args){//构造依赖注入容器IServiceCollection services = new ServiceCollection();//注入Person单例,生命周期暂时不展开services.AddSingleton<Person>();var builder = services.BuildServiceProvider();//初始化单例var res = builder.GetService<Person>();res.Name = "小刘";res.Age = 15;Console.WriteLine(JsonConvert.SerializeObject(res));//从容器中拿到Person单例,确认是否已被赋值为小刘var res2 = builder.GetService<Person>();Console.WriteLine(JsonConvert.SerializeObject(res2));//修改单例,查看容器中的单例是否被修改res2.Name = "小红";res2.Age = 23;//再从容器中拿出单例var res3 = builder.GetService<Person>();Console.WriteLine(JsonConvert.SerializeObject(res3));Console.WriteLine("Hello, World!");Console.ReadKey();}}
}

打印结果

在这里插入图片描述
这个说明这个单例一旦被修改了,容器中的数据就会被修改。但是这样仅仅是和全局静态的效果一样。依赖注入没有这么简单

自动装配

自动装配的意思就是自动依赖注入。就是你不需要主动去声明构造函数,IOC容器会自动帮你去使用构造函数。

举例

这里为了简单说明,这里只使用单例自动装配举例。

namespace IOC_Test.Models
{public class Person{public int Id { get; set; }public string Name { get; set; }public int Age {  get; set; }   }
}
namespace IOC_Test.Services
{public class PersonService{public Person Person { get; set; }/// <summary>/// 无参构造函数/// </summary>public PersonService() {Person = new Person();}/// <summary>/// 有参构造函数,IOC是选择尽可能多的参数构造/// </summary>/// <param name="person"></param>public PersonService(Person person){this.Person = person;}}
}

自动装配测试用例

using IOC_Test.Models;
using IOC_Test.Services;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;namespace IOC_Test
{internal class Program{static void Main(string[] args){IServiceCollection services = new ServiceCollection();//注入依赖services.AddSingleton<Person>();services.AddSingleton<PersonService>();//生成IOC容器var builder = services.BuildServiceProvider();//两次打印,第一次打印PersonService的Person{var res = builder.GetService<PersonService>();Console.WriteLine(JsonConvert.SerializeObject(res?.Person));}//修改Person,看看PersonService里面是不是会受影响{var res = builder.GetService<Person>();res.Name = "小王";res.Age = 10;}//再次打印,如果被修改,那么就说明是自动装配。如果没被修改,就说明没有将Person自动注入到PersonService{var res = builder.GetService<PersonService>();Console.WriteLine(JsonConvert.SerializeObject(res?.Person));}Console.WriteLine("Hello, World!");Console.ReadLine();}}
}

打印结果

在这里插入图片描述

自动装配执行顺序

测试用例

这里我们新建一个Dog

namespace IOC_Test.Models
{public class Dog{public int Id { get; set; }public string Name { get; set; }public int Age { get; set; }}
}

Person

namespace IOC_Test.Models
{public class Person{public int Id { get; set; }public string Name { get; set; }public int Age {  get; set; }   }
}

PersonService

namespace IOC_Test.Services
{public class PersonService{public Person Person { get; set; }public Dog Dog { get; set; }/// <summary>/// 无参构造函数/// </summary>public PersonService() {Person = new Person();}}
}

主函数

namespace IOC_Test
{internal class Program{static void Main(string[] args){IServiceCollection services = new ServiceCollection();//注入依赖services.AddSingleton<Person>();services.AddSingleton<PersonService>();services.AddSingleton<Dog>();//生成IOC容器var builder = services.BuildServiceProvider();//两次打印,第一次打印PersonService{var res = builder.GetService<PersonService>();Console.WriteLine(JsonConvert.SerializeObject(res));}//修改Person和Dog,看看PersonService里面是不是会受影响{var person = builder.GetService<Person>();person.Name = "小王";person.Age = 10;var dog = builder.GetService<Dog>();dog.Name = "旺财";dog.Age = 2;}//再次打印,查看自动装配如何执行{var res = builder.GetService<PersonService>();Console.WriteLine(JsonConvert.SerializeObject(res));}Console.WriteLine("Hello, World!");Console.ReadLine();}}
}
有歧义构造函数
namespace IOC_Test.Services
{public class PersonService{public Person Person { get; set; }public Dog Dog { get; set; }/// <summary>/// 无参构造函数/// </summary>public PersonService() {Person = new Person();}public PersonService(Person person){this.Person = person;}public PersonService(Dog dog) {this.Dog = dog;}}
}

如果构造函数出现歧义,比如这里既可以选择Person构造,又可以选择Dog构造,会报错
在这里插入图片描述

渐进式构造函数
namespace IOC_Test.Services
{public class PersonService{public Person Person { get; set; }public Dog Dog { get; set; }/// <summary>/// 无参构造函数/// </summary>public PersonService() {Person = new Person();}public PersonService(Person person){this.Person = person;}public PersonService(Person person,Dog dog) {this.Person= person;this.Dog = dog;}}
}

运行成功
在这里插入图片描述

循环依赖

Person注入Dog,Dog注入Person,看看效果如何

namespace IOC_Test.Models
{public class Person{public Dog Dog { get; set; }public int Id { get; set; }public string Name { get; set; }public int Age { get; set; }public Person(Dog dog){Dog = dog;}}
}
namespace IOC_Test.Models
{public class Dog{public int Id { get; set; }public string Name { get; set; }public int Age { get; set; }public Person Person { get; set; }public Dog(Person person){Person = person;}}
}

在这里插入图片描述

自动装配结论

自动装配是尽可能主动去装配服务,如果出现装配歧义,循环依赖,那么就会主动抛出异常。自动装配可以极大的减少对构造函数维护,我们不需要知道服务是怎么声明的,IOC容器会帮助我们自动声明相互之间的依赖。这张图就能很好的解释自动装配的效果

在这里插入图片描述

手动装配

自动装配是由IOC容器自动装配的类。如果需要装配多个同类的服务,那就要手动进行区别了。

手动注入

internal class Program
{static void Main(string[] args){IServiceCollection services = new ServiceCollection();services.AddSingleton<Person>(sp =>{var res = new Person() {Name = "小红",Age = 19};return res;});//生成容器var builder = services.BuildServiceProvider();{var res = builder.GetService<Person>();Console.WriteLine(JsonConvert.SerializeObject(res));}Console.WriteLine("Hello, World!");Console.ReadLine();}
}

在这里插入图片描述

别名注入

namespace IOC_Test
{internal class Program{static void Main(string[] args){IServiceCollection services = new ServiceCollection();services.AddKeyedSingleton<Person>("A",(sp,key) =>{var res = new Person() {Name = "小红",Age = 19};return res;});services.AddKeyedSingleton<Person>("B", (sp, key) =>{var res = new Person(){Name = "小蓝",Age = 23};return res;});//生成容器var builder = services.BuildServiceProvider();//获取服务,当Key找不到时自动返回Null{var res = builder.GetService<Person>();Console.WriteLine("获取默认服务");Console.WriteLine(JsonConvert.SerializeObject(res));}{var res = builder.GetKeyedService<Person>("A");Console.WriteLine("获取A,Person");Console.WriteLine(JsonConvert.SerializeObject(res));}{var res = builder.GetKeyedService<Person>("B");Console.WriteLine("获取B,Person");Console.WriteLine(JsonConvert.SerializeObject(res));}Console.WriteLine("Hello, World!");Console.ReadLine();}}
}

在这里插入图片描述

声明别名的服务将不会自动装配,即使声明的别名相同。建议使用多个不同名的服务来自动装配。手动声明别名需要手动装配对应关系

也可以在输入的时候主动拿到按照Key去寻找服务。

internal class Program
{static void Main(string[] args){IServiceCollection services = new ServiceCollection();//依赖注入是使用的时候去构造,所以声明顺序不影响实际运行顺序,有点类似于回调函数services.AddKeyedSingleton<Person>("A",(sp,key) =>{//Console.WriteLine(key);var res = new Person() {Name = "小红",Age = 19};return res;});services.AddKeyedSingleton<PersonService>("A", (sp, key) =>{return new PersonService(sp.GetKeyedService<Person>(key));});//生成容器var builder = services.BuildServiceProvider();//获取服务{var res = builder.GetKeyedService<Person>("A");Console.WriteLine("获取默认服务");Console.WriteLine(JsonConvert.SerializeObject(res));}//获取服务{var res = builder.GetKeyedService<PersonService>("A");Console.WriteLine("获取默认服务");Console.WriteLine(JsonConvert.SerializeObject(res));}Console.WriteLine("Hello, World!");Console.ReadLine();}
}

依赖注入的构造顺序

依赖注入是使用的时候去生成,而不是注入的时候生成

namespace IOC_Test
{internal class Program{static void Main(string[] args){IServiceCollection services = new ServiceCollection();services.AddKeyedSingleton<Person>("A",(sp,key) =>{Console.WriteLine($"构造函数执行,key[{key}]");var res = new Person() {Name = "小红",Age = 19};return res;});//生成容器var builder = services.BuildServiceProvider();//获取服务{Console.WriteLine("获取Key[A]服务");var res = builder.GetKeyedService<Person>("A");Console.WriteLine(JsonConvert.SerializeObject(res));}Console.WriteLine("Hello, World!");Console.ReadLine();}}
}

在这里插入图片描述

结尾

IOC容器还有许多别的功能,比如别名,接口注入,注解注入,声明周期等。这个我还不太了解。现在的单例自动装配已经基本满足了我的功能,我以后有时间会去深入了解。

这篇关于.NET Core 依赖注入 Microsoft.Extensions.DependencyInjection的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/482313

相关文章

每天认识几个maven依赖(ActiveMQ+activemq-jaxb+activesoap+activespace+adarwin)

八、ActiveMQ 1、是什么? ActiveMQ 是一个开源的消息中间件(Message Broker),由 Apache 软件基金会开发和维护。它实现了 Java 消息服务(Java Message Service, JMS)规范,并支持多种消息传递协议,包括 AMQP、MQTT 和 OpenWire 等。 2、有什么用? 可靠性:ActiveMQ 提供了消息持久性和事务支持,确保消

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

2、PF-Net点云补全

2、PF-Net 点云补全 PF-Net论文链接:PF-Net PF-Net (Point Fractal Network for 3D Point Cloud Completion)是一种专门为三维点云补全设计的深度学习模型。点云补全实际上和图片补全是一个逻辑,都是采用GAN模型的思想来进行补全,在图片补全中,将部分像素点删除并且标记,然后卷积特征提取预测、判别器判别,来训练模型,生成的像

pip-tools:打造可重复、可控的 Python 开发环境,解决依赖关系,让代码更稳定

在 Python 开发中,管理依赖关系是一项繁琐且容易出错的任务。手动更新依赖版本、处理冲突、确保一致性等等,都可能让开发者感到头疼。而 pip-tools 为开发者提供了一套稳定可靠的解决方案。 什么是 pip-tools? pip-tools 是一组命令行工具,旨在简化 Python 依赖关系的管理,确保项目环境的稳定性和可重复性。它主要包含两个核心工具:pip-compile 和 pip

深入理解数据库的 4NF:多值依赖与消除数据异常

在数据库设计中, "范式" 是一个常常被提到的重要概念。许多初学者在学习数据库设计时,经常听到第一范式(1NF)、第二范式(2NF)、第三范式(3NF)以及 BCNF(Boyce-Codd范式)。这些范式都旨在通过消除数据冗余和异常来优化数据库结构。然而,当我们谈到 4NF(第四范式)时,事情变得更加复杂。本文将带你深入了解 多值依赖 和 4NF,帮助你在数据库设计中消除更高级别的异常。 什么是

PHP防止SQL注入详解及防范

SQL 注入是PHP应用中最常见的漏洞之一。事实上令人惊奇的是,开发者要同时犯两个错误才会引发一个SQL注入漏洞。 一个是没有对输入的数据进行过滤(过滤输入),还有一个是没有对发送到数据库的数据进行转义(转义输出)。这两个重要的步骤缺一不可,需要同时加以特别关注以减少程序错误。 对于攻击者来说,进行SQL注入攻击需要思考和试验,对数据库方案进行有根有据的推理非常有必要(当然假设攻击者看不到你的

PHP防止SQL注入的方法(2)

如果用户输入的是直接插入到一个SQL语句中的查询,应用程序会很容易受到SQL注入,例如下面的例子: $unsafe_variable = $_POST['user_input'];mysql_query("INSERT INTO table (column) VALUES ('" . $unsafe_variable . "')"); 这是因为用户可以输入类似VALUE”); DROP TA

PHP防止SQL注入的方法(1)

(1)mysql_real_escape_string – 转义 SQL 语句中使用的字符串中的特殊字符,并考虑到连接的当前字符集 使用方法如下: $sql = "select count(*) as ctr from users where username ='".mysql_real_escape_string($username)."' and password='". mysql_r

PHP7扩展开发之依赖其他扩展

前言 有的时候,我们的扩展要依赖其他扩展。比如,我们PHP的mysqli扩展就依赖mysqlnd扩展。这中情况下,我们怎么使用其他扩展呢?这个就是本文讲述的内容。 我们新建立一个扩展,名字叫 demo_dep , 依赖之前的say扩展。 在demo_dep扩展中,我们实现demo_say方法。这个方法调用say扩展的say方法。 代码 基础代码 确保say扩展的头文件正确安装到了php