首页 > 其他分享 >如何在.net6webapi中实现自动依赖注入

如何在.net6webapi中实现自动依赖注入

时间:2023-06-08 17:56:05浏览次数:51  
标签:容器 生命周期 net6webapi 依赖 services public 注入

IOC/DI

IOC(Inversion of Control)控制反转:控制反正是一种设计思想,旨在将程序中的控制权从程序员转移到了容器中。容器负责管理对象之间的依赖关系,使得对象不再直接依赖于其他对象,而是通过依赖注入的方式来获取所需的资源。

ID(Dependency Injection)依赖注入:他是IOC的具体实现方式之一,使用最为广泛,DI通过在运行时动态地将某个依赖关系抽象为独立的组件,提交到容器之中,需要使用时再由容器注入,提升组件重用的频率,为系统搭建一个灵活,可扩展的平台。

IOC/DI是一种设计模式,用于解耦组件之间的依赖关系。在传统的编程模式中,组件之间的依赖关系是硬编码在代码中的,这样会导致代码的耦合度很高,难以维护和发展。而IOC/DI模式则是通过将组件之间的依赖关系交给容器来管理,组件不再直接依赖其他组件,而是通过容器来获取所依赖的对象。这样可以使组件之间的依赖关系更加灵活,容器可以根据需要动态地创建和管理组件,从而实现更好的可维护性和可扩展性。

如何在.net6webapi中使用依赖注入?

首先我们定义一个服务接口及对应的实现

    public interface ITestServices
    {
        int return123();
    }
    public class TestServices : ITestServices
    {
        public int return123()
        {
            return 123;
        }
    }

然后我们在Program.cs注入服务实现

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddTransient<ITestServices, TestServices>();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

值得注意的是依赖注入有三种生命周期

  • 作用域(Scoped):在应用程序启动时创建,并在应用程序关闭时销毁。这种类型的服务实例会被容器管理,但是只会被当前请求使用。当请求结束时,该服务实例会被销毁。
  • 单例(Singleton):在应用程序启动时创建,并在整个应用程序运行期间保持不变。这种类型的服务实例会被容器管理,并且可以被多个请求共享。
  • 瞬时(Transient):在应用程序启动时创建,并在应用程序关闭时销毁。这种类型的服务实例不会被容器管理,也不会被其他服务引用。

最后在需要使用的控制器中构造函数注入就可以使用了

    [Route("[controller]/[action]")]
    [ApiController]
    public class TestController : ControllerBase
    {
        private readonly ITestServices _testServices;
        public TestController(ITestServices testServices)
        {
            _testServices= testServices;
        }

        [HttpGet]
        public int Get123() => _testServices.return123();
    }

 怎么实现自动注入?

依赖注入好归好,就是每个服务都得在Program.cs注入服务实现,一但服务多起来,麻烦不说,Program.cs中的代码更是会变得凌乱不堪,可能会有小伙伴说,可以开一个扩展函数单独做注入,但私以为,既然有一种方法可以一劳永逸,何乐而不为呢?

其实现便是利用.net的高级特性之一,反射

首先我们定义三个生命周期接口,其对应依赖注入的三种生命周期

    //瞬时注入服务接口
    public interface ITransient
    { }

    //作用域注入服务接口
    public interface IScoped
    { }

    //单例注入服务接口
    public interface ISingleton
    { }

然后我们定义自动注入的扩展方法,其为核心实现

        public static IServiceCollection RegisterAllServices(this IServiceCollection services)
        {
            //获取当前程序集
            var entryAssembly = Assembly.GetEntryAssembly();

            //获取所有类型
            //!. null包容运算符,当你明确知道表达式的值不为null 使用!.(即null包容运算符)可以告知编译器这是预期行为,不应发出警告
            //例: entryAssembly!.GetReferencedAssemblies() 正常
            //entryAssembly.GetReferencedAssemblies() 编译器判断entryAssembly有可能为null,变量下方出现绿色波浪线警告

            var types = entryAssembly!.GetReferencedAssemblies()//获取当前程序集所引用的外部程序集
                .Select(Assembly.Load)//装载
                .Concat(new List<Assembly>() { entryAssembly })//与本程序集合并
                .SelectMany(x => x.GetTypes())//获取所有类
                .Distinct();//排重

            //三种生命周期分别注册
            Register<ITransient>(types, services.AddTransient, services.AddTransient);
            Register<IScoped>(types, services.AddScoped, services.AddScoped);
            Register<ISingleton>(types, services.AddSingleton, services.AddSingleton);

            return services;
        }

        /// <summary>
        /// 根据服务标记的生命周期interface,不同生命周期注册到容器里面
        /// </summary>
        /// <typeparam name="TLifetime">注册的生命周期</typeparam>
        /// <param name="types">集合类型</param>
        /// <param name="register">委托:成对注册</param>
        /// <param name="registerDirectly">委托:直接注册服务实现</param>
        private static void Register<TLifetime>(IEnumerable<Type> types, Func<Type, Type, IServiceCollection> register, Func<Type, IServiceCollection> registerDirectly)
        {
            //找到所有标记了Tlifetime生命周期接口的实现类
            var tImplements = types.Where(x => x.IsClass && !x.IsAbstract && x.GetInterfaces().Any(tinterface => tinterface == typeof(TLifetime)));

            //遍历,挨个以其他所有接口为key,当前实现为value注册到容器中
            foreach (var t in tImplements)
            {
                //获取除生命周期接口外的所有其他接口
                var interfaces = t.GetInterfaces().Where(x => x != typeof(TLifetime));
                if (interfaces.Any())
                {
                    foreach (var i in interfaces)
                    {
                        register(i, t);
                    }
                }

                //有时需要直接注入实现类本身
                registerDirectly(t);
            }
        }

其核心逻辑便是通过反射扫描程序集,当扫描到实现了我们定义的生命周期接口时,为其实现对应的生命周期注入。

注册这个服务

builder.Services.RegisterAllServices();

然后我们就可以通过继承生命周期接口来实现自动服务注入

    public interface ITestServices
    {
        int return123();
    }
    public class TestServices : ITestServices, ITransient
    {
        public int return123()
        {
            return 123;
        }
    }

接下来无需在Program.cs注入服务实现

 调用成功。

自动注入代码参考自:【NetCore】依赖注入的一些理解与分享 - wosperry - 博客园 (cnblogs.com)

标签:容器,生命周期,net6webapi,依赖,services,public,注入
From: https://www.cnblogs.com/SaoJian/p/17462782.html

相关文章

  • Redhat8安装MySQL8操作方法(超简单Linux无依赖安装mysql数据库)
    一、安装说明1.1、相关说明:Redhat8在线安装Mysql8数据库,使操作系统找到并自动安装自适应的版本及相关依赖组件;1.2、系统版本 二、安装方法2.1、下载应用软件[root@GuoDC~]#wgethttps://dev.mysql.com/get/mysql80-community-release-el8-4.noarch.rpm 2.2、安装应用......
  • 注入属性Autowire和Qualifier
    @Autowire根据属性类型注入使用:在server包使用注解@server创建对象在dao包使用注解@Repository创建对象在dao包使用注解@Autowire装载server包对象具体实现:在server包创建UserServer类,并加注解@server在dao包创建UserDao接口和UserDaoImpl实现类,在实现类加注解@Repository......
  • Makefile基础教程(自动生成依赖关系)
    @TOC前言在前面的文章中我们都只使用到了.c文件作为依赖但是在实际的工程中肯定是不可能只有.c文件的还存在.h文件,那么在包含了.h文件后又该如何来包含依赖关系呢?一、makefile不包含.h依赖的后果首先先在目录下新建四个文件夹,其中就包含了fun.h这个文件。makefile:OBJS:=fun.omai......
  • DIY制作隔离信号注入变压器
     最近在学习模电知识,接触到了测量运放环路增益,需要使用合适的注入变压器,查找资料发现商用信号注入变压器价格昂贵,不适合个人学习使用。看到LOTO使用普通音频变压器做测试,也跟技术群友做了交流,尝试使用各种变压器、共模电感做测试,效果都不太理想。在逛某鱼时发现有位大神在出售自......
  • 解决使用yarn安装依赖出现“The engine "node" is incompatible with this module. Ex
    1、问题描述某天在使用yarn安装依赖的时候,突然出现如下错误导致安装依赖终止:Theengine"node"isincompatiblewiththismodule.Expectedversion"^14.18.0||^16.14.0||>=18.0.0".Got"17.9.0"2、解决办法使用如下命令忽略错误:yarnconfigsetignore-enginestr......
  • WPF学习笔记一 依赖属性及其数据绑定
    本文想通过由浅入深的讲解让读者比较深的理解依赖属性. 首先,我们回顾一下依赖属性的发展历史. 最初,人们提出面向对象编程时,并没有属性这个说法,当时叫做成员变量.一个对象由成员变量和成员函数组成,如下:PublicClassA{PublicintIndex;//成员变量PublicvoidFu......
  • Spring 学习笔记(4)—— Bean 的基本配置、依赖注入(DI)、注入参数引用其他Bean
    一、Bean的基本配置1装配一个Bean在Spring容器的配置文件中定义一个简要Bean的配置片段2Bean的命名二、依赖注入1属性注入属性注入要求Bean提供一个默认的构造函数,并为需要注入的属性提供对应的Setter方法。2构造函数注入按索引匹配入参三、注入参数引用其他Bean......
  • Jmeter-依赖登录的接口测试
    JMETER接口测试问题解决二之后续接口请求依赖登录接口的操作-知识在于点滴的积累-博客园(cnblogs.com)问题现象:必须登录才能测试其他接口解决办法:    用到了http授权管理器和httpcookie管理器。注意:  要先判断当前的登录的token是在header中的Authorizat......
  • Jmeter-依赖上一个接口的响应数据
    问题:  下一个接口的入参需要依赖上一个接口的响应.如: 修改客户请求需要依赖添加客户请求响应中的id 1. 在上一个接口的请求中添加后置处理器:2. 将响应中的出参设置为变量 3. 在下一个接口的请求中使用变量  4. 请求成功  ......
  • RDS 、HDFS、 mapreduce 、spark 、hive、 hbase 、zookeeper 、kafka 、flume、mysql
    这些技术是大数据领域的常用组件,它们之间的配置文件依赖关系如下:RDS是一种关系型数据库,可以独立安装和使用,不需要依赖其他组件。HDFS是Hadoop分布式文件系统,通常与MapReduce一起使用。在Hadoop集群中,HDFS需要配置core-site.xml和hdfs-site.xml两个文件,其中core-site......