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中实现自动依赖注入的更多相关文章

  1. PHP反射机制实现自动依赖注入

    依赖注入又叫控制反转,使用过框架的人应该都不陌生.很多人一看名字就觉得是非常高大上的东西,就对它望而却步,今天抽空研究了下,解开他它的神秘面纱.废话不多说,直接上代码: /* * * * 工具类,使用 ...

  2. 转:深入浅出spring IOC中四种依赖注入方式

    转:https://blog.csdn.net/u010800201/article/details/72674420 深入浅出spring IOC中四种依赖注入方式 PS:前三种是我转载的,第四种是 ...

  3. 新项目升级到JFinal3.5之后的改变-着重体验自动依赖注入

    最近,JFinal3.5发布,喜大普奔,我也应JBolt用户的需求,将JBolt进行了升级,实现可配置自动注入开启,支持JFinal3.5的项目生成.具体可以看:JBolt升级日志 这等工作做完后,我 ...

  4. 几十行代码实现ASP.NET Core自动依赖注入

    在开发.NET Core web服务的时候,我们习惯使用自带的依赖注入容器来进行注入. 于是就会经常进行一个很频繁的的重复动作:定义一个接口->写实现类->注入 有时候会忘了写Add这一步 ...

  5. 【17MKH】我在框架中对.Net依赖注入的扩展

    说明 依赖注入(DI)是控制反转(IoC)的一种技术实现,它应该算是.Net中最核心,也是最基本的一个功能.但是官方只是实现了基本的功能和扩展方法,而我呢,在自己的框架 https://github. ...

  6. 如何在WORD2010中取消自动编号?

    如何在WORD2010中取消自动编号? 使用WORD2010有一个很大的问题就是WORD2010的自动编号问题,WORD2010的自动编号是符合外国人的写作习惯的,对中国人来说不适用. WORD201 ...

  7. 为什么多线程、junit 中无法使用spring 依赖注入?

    为什么多线程.junit 中无法使用spring 依赖注入? 这个问题,其实体现了,我们对spring已依赖太深,以至于不想自己写实例了. 那么到底是为什么在多线程和junit单元测试中不能使用依赖注 ...

  8. 深入浅出spring IOC中三种依赖注入方式

    深入浅出spring IOC中三种依赖注入方式 spring的核心思想是IOC和AOP,IOC-控制反转,是一个重要的面向对象编程的法则来消减计算机程序的耦合问题,控制反转一般分为两种类型,依赖注入和 ...

  9. ASP.NET Core中如影随形的”依赖注入”[下]: 历数依赖注入的N种玩法

    在对ASP.NET Core管道中关于依赖注入的两个核心对象(ServiceCollection和ServiceProvider)有了足够的认识之后,我们将关注的目光转移到编程层面.在ASP.NET ...

  10. ASP.NET Core中如影随形的”依赖注入”[上]: 从两个不同的ServiceProvider说起

    我们一致在说 ASP.NET Core广泛地使用到了依赖注入,通过前面两个系列的介绍,相信读者朋友已经体会到了这一点.由于前面两章已经涵盖了依赖注入在管道构建过程中以及管道在处理请求过程的应用,但是内 ...

随机推荐

  1. Kafka 事务

    更多内容,前往IT-BLOG 在了解 Kafka的事务之前,先说一下 Kafka中幂等和事务(Kafka 0.11.0.0版本引入的两个特性)以此来实现 Exactly once(精确一次)了解更多链 ...

  2. 二进制安装Kubernetes(k8s) v1.24.1 IPv4/IPv6双栈

    二进制安装Kubernetes(k8s) v1.24.1 IPv4/IPv6双栈 Kubernetes 开源不易,帮忙点个star,谢谢了 介绍 kubernetes二进制安装 后续尽可能第一时间更新 ...

  3. PySimpleGU之运行多个窗口

    这是PySimpleGUI继续简单的地方,但是问题空间刚刚进入了"复杂"领域. 如果您希望在事件循环中运行多个窗口,则有两种方法可以执行此操作. 当第二个窗口可见时,第一个窗口不会 ...

  4. 四月十八日java基础知识

    1.由于每个对象的pi值都是相同的,所以没有必要让每个对象都保存有自己的pi值,因此将pi声明为静态变量,使之成为所有对象共用的存储空间,所有对象都公用pi这个变量也就是说共用的变量可以设定为静态变量 ...

  5. Carla 自动驾驶仿真平台的安装与配置指南

    简介 Carla 是一款基于 Python 编写和 UE(虚幻引擎)的开源仿真器,用于模拟自动驾驶车辆在不同场景下的行为和决策.它提供了高度可定制和可扩展的驾驶环境,包括城市.高速公路和农村道路等.C ...

  6. JS 对输入框进行限制(常用的都有)

    文章来源 http://www.soso.io/article/24096.html 1.文本框只能输入数字代码(小数点也不能输入) 代码如下: <input οnkeyup="thi ...

  7. Go语言实现基于HTTP的内存缓存服务

    所有的缓存数据都存储在服务器的内存中,因此重启服务器会导致数据丢失,基于HTTP通信会将使开发变得简单,但性能不会太好 缓存服务接口 本程序采用REST接口,支持设置(Set).获取(Get)和删除( ...

  8. Yapi及Swgger使用+注解

    1.Yapi 1.1 介绍 YApi 是高效.易用.功能强大的 api 管理平台,旨在为开发.产品.测试人员提供更优雅的接口管理服务.可以帮助开发者轻松创建.发布.维护 API,YApi 还为用户提供 ...

  9. RHEL 7配置HAProxy实现Web负载均衡

    本文将简单介绍使用HAProxy实现web负载均衡,主要内容包括基于权重的轮询.为HAProxy配置https.配置http重定向为https.配置HAProxy使用独立日志. 一.测试环境 HAPr ...

  10. [C++基础入门] 6、 函数

    文章目录 6 函数 6.1 概述 6.2 函数的定义 6.3 函数的调用 6.4 值传递 6.5 函数的常见样式 6.6 函数的声明 6.7 函数的分文件编写 6 函数 6.1 概述 **作用:**将 ...