首页 > 其他分享 >.Net WebApi中实现自动依赖注入的三种方法

.Net WebApi中实现自动依赖注入的三种方法

时间:2024-03-16 09:01:46浏览次数:28  
标签:WebApi 程序 busType var 三种 typeof services Net busInterface

前言

该文仅供学习参考,如有问题请指正。

依赖关系注入 (DI) ,是一种软件设计模式,这是一种在类及其依赖项之间实现控制反转 (IoC) 的技术。 .NET 中的依赖关系注入是框架的内置部分,与配置、日志记录和选项模式一样。

生命周期

依赖注入有以下三种生命周期

  • 瞬时 (Transient): 每次从服务容器进行请求时创建的,请求结束后销毁, 这种生存期适合轻量级、 无状态的服务。
  • 作用域(Scoped):在指定的范围内,第一次请求时会创建一个实例,重复请求时,会返回同一个实例,在处理请求的应用中,请求结束时会释放有作用域的服务。使用 Entity Framework Core 时,默认情况下 AddDbContext 扩展方法使用范围内生存期来注册 DbContext 类型。
  • 单例(Singleton):单例生命周期是最长的生命周期,整个应用程序只会创建一个服务实例。这种生命周期适用于那些需要在整个应用程序中共享状态的服务,例如配置(Configuration)类、缓存(Cache)类等。

用反射实现自动依赖注入

定义三种生命周期的接口类

    /// <summary>
    /// 注入标记,Scoped作用域,每次请求时创建一次
    /// </summary>
    public interface IScopedDependency
    {
    }

    /// <summary>
    /// 注入标记,生命周期Singleton,服务第一次请求时创建,后续请求都使用相同的实例
    /// </summary>
    public interface ISingletonDependency
    {
    }

    /// <summary>
    /// 注入标记,生命周期Transient,每次请求时被创建,适合轻量级服务
    /// </summary>
    public interface ITransientDependency
    {
    }
}

通过GetReferencedAssemblies实现

GetReferencedAssemblies该方法只能获取当前程序集所引用的外部程序集,不能获取模式分离/间接引用的程序集
https://www.cnblogs.com/qianxingmu/p/13363193.html 参考地址

/// <summary>
/// 动态注册所有服务
/// 约定:Interfaces(注入接口), IScopedDependency(生命周期),可以有泛型接口,其它不能再继承。
/// 注意只能注入直接引用的,间接引用的不行
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddDynamicinjectionService(this IServiceCollection services)
{
	//当前程序集
	var entryAssembly = Assembly.GetEntryAssembly();
	//获取当前程序集所引用的外部程序集,不能获取模式分离/间接引用的程序集
	var types = entryAssembly!.GetReferencedAssemblies()
		.Select(Assembly.Load)//装载
		.Concat(new List<Assembly>() { entryAssembly })//与本程序集合并
		.SelectMany(x => x.GetTypes())//获取所有类
		.Where(x => !x.IsAbstract && x.IsClass)//排除抽象类
		.Distinct();
	//获取所有继承服务标记的生命周期实现类
	var busTypes = types.Where(x => x.GetInterfaces().Any(t =>
					   t == typeof(ITransientDependency)
					|| t == typeof(IScopedDependency)
					|| t == typeof(ISingletonDependency));

	foreach (var busType in busTypes)
	{
		//过滤泛型接口
		var busInterface = busType.GetInterfaces()
			.Where(t => t != typeof(ITransientDependency)
						   && t != typeof(IScopedDependency)
						   && t != typeof(ISingletonDependency)
						   && !t.IsGenericType)
			.FirstOrDefault();
		
		if (busInterface == null) continue;
		
		if (typeof(ITransientDependency).IsAssignableFrom(busType))
			services.AddTransient(busInterface, busType);
		if (typeof(IScopedDependency).IsAssignableFrom(busType))
			services.AddScoped(busInterface, busType);
		if (typeof(ISingletonDependency).IsAssignableFrom(busType))
			services.AddSingleton(busInterface, busType);
	}
	return services;
}

在Program.cs 中添加该服务
builder.Services.AddDynamicinjectionService();

加载程序集路径实现

只自动注入该程序集路径下的服务,并且需要约定文件名称

/// <summary>
/// 把系统所有Business添加到ServiceCollection
/// 加载程序集路径动态注入
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddBusService(this IServiceCollection services)
{
	string rootPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
	var busAssembly = Assembly.LoadFrom(Path.Combine(rootPath, "WenYan.Service.Business.dll"));
	var busTypes = busAssembly.GetTypes().Where(w => w.Name.EndsWith("Business")).ToList();
	foreach (var busType in busTypes)
	{
		var busInterface = busType.GetInterfaces().Where(w => w.Name.EndsWith("Business")).FirstOrDefault();
		if (busInterface == null) continue;
		if (typeof(ITransientDependency).IsAssignableFrom(busType))
			services.AddTransient(busInterface, busType);
		if (typeof(IScopedDependency).IsAssignableFrom(busType))
			services.AddScoped(busInterface, busType);
		if (typeof(ISingletonDependency).IsAssignableFrom(busType))
			services.AddSingleton(busInterface, busType);
	}
	return services;
}

通过依赖注入拓展库:Scrutor,使用非常简单,主要通过 FromAssemblyOf<> 扫描程序集和 AddClasses(o) 进行筛选注册

https://github.com/khellang/Scrutor 相关详细文档

services.Scan(scan => scan
    // 扫描特定类型所在的程序集,这里是 ITransientService 所在的程序集
    .FromAssemblyOf<ITransientService>()
        // .AddClasses 在上面获取到的程序集中扫描所有公开、非抽象类型
        // 之后可以通过委托进行类型筛选,例如下面只扫描实现 ITransientService 的类型
        .AddClasses(classes => classes.AssignableTo<ITransientService>())
            // 将上面的类型作为它实现的所有接口进行注册
            // 如果类型实现了 N 个接口,那么就会有三个独立的注册
            .AsImplementedInterfaces()
            // 最后指定注册的生存期,如瞬时,作用域,还是单例
            .WithTransientLifetime()
        // 重复上面操作,比如这里扫描 IScopedService 所在的程序集
        .AddClasses(classes => classes.AssignableTo<IScopedService>())
            // 这里和上面不一样的是,这里指定只实现特定的几口,也就是只注册一次
            .As<IScopedService>()
            // 指定注册的生存期
            .WithScopedLifetime()
        // 也支持泛型注册,单个泛型参数
        .AddClasses(classes => classes.AssignableTo(typeof(IOpenGeneric<>)))
            .AsImplementedInterfaces()
        // 多个泛型参数
        .AddClasses(classes => classes.AssignableTo(typeof(IQueryHandler<,>)))

参考链接

https://www.cnblogs.com/SaoJian/p/17462782.html
https://www.cnblogs.com/qianxingmu/p/13363193.html
https://furion.net/docs/dependency-injection
https://juejin.cn/post/7211158239135383611

标签:WebApi,程序,busType,var,三种,typeof,services,Net,busInterface
From: https://www.cnblogs.com/wenyan9-29/p/18076682

相关文章

  • .Net Core 你必须知道的source-generators
    源生成器是C#9中引入的一项功能,允许在编译过程中动态生成代码。它们直接与C#编译器集成(Roslyn)并在编译时运行,分析源代码并根据分析结果生成附加代码。源生成器提供了一种简化的自动化代码生成方法,无需外部工具或单独的预编译步骤。通过无缝集成到编译过程中,源生成器可......
  • R语言弹性网络Elastic Net正则化惩罚回归模型交叉验证可视化
    原文链接:http://tecdat.cn/?p=26158原文出处:拓端数据部落公众号 弹性网络正则化同时应用L1范数和L2范数正则化来惩罚回归模型中的系数。为了在R中应用弹性网络正则化。在 LASSO回归中,我们为alpha参数设置一个'1'值,并且在岭回归中,我们将'0'值设置为其alpha参数......
  • KGAT Knowledge Graph Attention Network for Recommendation
    目录概符号说明KGATEmbeddingLayerAttentiveEmbeddingPropagationLayers代码WangX.,HeX.,CaoY.,LiuM.andChuaT.KGAT:Knowledgegraphattentionnetworkforrecommendation.KDD,2019.概知识图谱for推荐系统.符号说明\(\mathcal{G}_1=\{(u,y_{ui}......
  • Profinet转CC-Link网关使用指南
    本文为您提供CCLINK转Profinet网关(XD-PNCR20)使用指南,教您如何快速配置和集成网关,实现CCLINK与Profinet的互联。CCLINK转Profinet网关(XD-PNCR20)是一个经过自主研发的先进设备,CCLINK转Profinet网关设备的研发旨在实现CCLINK总线和Profinet网络之间的完美连接,从而实现各种总线系统的......
  • 西门子S7.NET通信库执行【写】操作的实践与优化
    本文将深入探讨如何使用西门子S7.NET通信库执行写操作,并分享一些实践中的优化经验。我们将从基本概念、写操作流程、效率影响因素、性能测试与优化、常见错误及避免方法,以及面向对象的通信库使用示例等方面进行详细讲解。一、西门子S7.NET通信库的基本概念和功能西门子S7.......
  • [.NET项目实战] Elsa开源工作流组件应用(一): Elsa工作流简介
    Elsa工作流简介工作流是什么?引用维基百科中对工作流的解释:是对工作流程及其各操作步骤之间业务规则的抽象、概括、描述。工作流建模,即将工作流程中的工作如何前后组织在一起的逻辑和规则在计算机中以恰当的模型进行表示并对其实施计算Elsa是一个功能强大的工作流库,支持在任......
  • AspNetCore8.0实战
    前言想变优秀的第N天。学习张老师的Blog.Core。1.创建Asp.NetCoreAPI1.1创建项目启用OpenAPI:sawgger不适用顶级语句:使用main函数使用控制器:controller1.2配置说明iisSettings:iis配置。http:kestrl启动配置。IISExpress:iis启动配置。2.仓储+服务创建以下公共类......
  • 深入理解.NET集合框架:类型与用途
    在这篇博客中,我们将详细探讨.NET集合框架的各个成员,以及它们的特点和适用场景。了解这些集合类型对于编写高效、可靠的.NET应用程序至关重要。以下是.NET集合框架中一些最常用的集合类型的概述:一、数组(Array)特点:固定长度,元素类型可以相同也可以不同。用法:适用于已知数据大小且......
  • 轻量级.net standard微信支付登录Nuget开源库
    我个人编写的库,在我个人网站,小程序等很多地方都在使用中,大家可以搜索小程序什邡市宅猫君网络工作室或者到我的网站store.zhaimaojun.cn 去体验支付和登录效果。本库主要实现了nativepay(二维码支付)jsapipay(小程序直接调起支付),需要注意的是这是基于api3的,非api2。以下演示如......
  • 聊一聊 MySQL 的 InnoDB 存储引擎以及三种日志
    楔子上一篇文章我们介绍了MySQL的基本架构,这里再来回顾一下。整个架构还是很好理解的,我们说MySQL分为Server层和存储引擎层。其中Server层包含了MySQL的大多数核心服务功能,而存储引擎层则负责提供数据的存储和读取,并且是插件式的,一个Server层支持不同的存储引擎层......