DotNetCore依赖注入实现批量注入
文章转载自平娃子(QQ:273206491):http://os.pingwazi.cn/resource/batchinjectservice
一、依赖注入
通过依赖注入,可以实现接口与实现类的松耦合。Asp.Net Core底层设计支持依赖注入。系统中存在的内置服务(Mvc、DbContext等等)的依赖注入和自定义服务的依赖注入。其中内置服务的依赖注入,可以直接调用IServiceCollection的扩展方法(AddMvc()、AddDbContext())。
二、.Net Core底层所实现的依赖注入功能
在使用.Net Core底层所实现的依赖注入功能之前呢,需要先理解依赖注入对象的三种生命周期:
1、Transent(瞬时)生命周期在他们每次请求的时候被创建,这一生命周期适合轻量级和无状态的服务。并且在一次请求中,如果存在多次获取这个实例,那这些实例也是不同的。
2、Scoped(范围)生命周期在每次请求的时候被创建,在一次请求中,如果存在多次获取这个实例,那么返回的也是同一个实例。
3、Singleton(单例)生命周期在它们第一次被请求的时候使用的时候创建,并且只创建一次,后续都是使用的同一个对象。
本实例使用.Net Core内置的依赖注入功能的步骤如下:
1、使用vs2017或者vs2019创建一个.Net Core WebApi项目
2、创建ISay接口,其中定义一个Say方法。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace IocPrictic
{
public interface ISay
{
string Say();
}
}
3、创建ISay的实现类ChinseSay
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace IocPrictic
{
public class ChinseSay : ISay
{
public string Say()
{
Console.WriteLine("我说中国话");
return "我说中国话";
}
}
}
4、在Startup中的ConfigureServices方法中注册ChineseSay服务。
services.AddTransient<ISay, ChinseSay>();
5、模板控制器中使用依赖注入的对象。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace IocPrictic.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
private ISay _ISay;
public ValuesController(ISay isay)
{
this._ISay = isay;
}
// GET api/values
[HttpGet]
public ActionResult<string> Get()
{
string sayResult= this._ISay.Say();
return sayResult;
}
}
}
三、利用反射实现批量的依赖注入
如果需要注入的对象有多个呢?可能是几十个也可能是几百个,如果全是认为的进行注入的话,这是一个非常麻烦的事情。因此这里引入了反射来实现批量注入的功能。
实现步骤(思想/算法/...)如下:
1、定义一个需要依赖注入的标记接口(INeedInject),这个接口里面什么也没有,仅仅标记一个接口需要进行依赖注入。
2、定义三个生命周期接口,这个三个接口里面什么也没有(ITransentInject、IScopeInject、ISingletonInject),仅仅作为一个类型,在利用反射的时候让其选择对应的生命周期注入方式。
3、定义一个不需要依赖注入的标记接口(INoNeedInject),这个接口是在我们需要更换接口实现类的时候,在旧的实现类上实现这个接口,让反射程序跳过这个实现类,去注入新的类。
4、生命周期接口继承需要依赖注入的标记接口(INeedInject)。
5、需要依赖注入的接口继承三种生命周期接口中的其中一种。
6、实现类实现需要依赖注入的接口。
7、利用反射更具标记接口(INeedInject)筛选出那些接口需要进行依赖注入。
8、利用反射找到这个需要进行依赖注入接口的唯一实现类。
9、根据接口定义的注入类型,选择合适的生命周期类型去实现注入。
10、调用依赖注入的对象
(1)、INeedInject
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace IocPrictic
{
public interface INeedInject
{
}
}
(2)、三种生命周期接口
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace IocPrictic
{
public interface ITransentInject:INeedInject
{
}
}
***********************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace IocPrictic
{
public interface IScopeInject:INeedInject
{
}
}
***********************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace IocPrictic
{
public interface ISingleTonInject:INeedInject
{
}
}
(3)、不需要依赖注入的标记接口
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace IocPrictic
{
public interface INoNeedInject
{
}
}
(4)、定义需要依赖注入的接口
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace IocPrictic
{
public interface ISay:ITransentInject
{
string Say();
}
}
***********************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace IocPrictic
{
public interface IEat:ITransentInject
{
string Eat();
}
}
(5)、定义实现类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace IocPrictic
{
public class ChinseEat : IEat
{
public string Eat()
{
Console.WriteLine("我吃中国餐");
return "我吃中国餐";
}
}
}
***********************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace IocPrictic
{
public class ChinseSay : ISay
{
private IEat _IEat;
public ChinseSay(IEat ieat)
{
this._IEat = ieat;
}
public string Say()
{
string eatResult=_IEat.Eat();
Console.WriteLine("我说中国话");
return $"我说中国话,{eatResult}";
}
}
}
(6)、利用反射实现依赖注入(核心)
在Startup中定义如下方法:
/// <summary>
/// 注册指定程序集中的服务
/// </summary>
/// <param name="assemblyNames">程序集名的字典</param>
/// <param name="services">IServiceCollection类型的对象</param>
public void BatchInjectService(IDictionary<string,string> assemblyNames,IServiceCollection services)
{
Type iNeedInject = typeof(INeedInject);
Type iTransentInject = typeof(ITransentInject);
Type iScopeInject = typeof(IScopeInject);
Type iSingletonInject = typeof(ISingleTonInject);
Type iNoNeedInject = typeof(INoNeedInject);//当接口切换实现类时,在旧的实现类上实现这个接口就ok
foreach (var assemblyItem in assemblyNames)
{
string assemblyInterName = assemblyItem.Key;
string assemblyObjName = assemblyItem.Key;
Type[] interTypes = Assembly.Load(assemblyInterName).GetTypes().Where(t =>t.IsInterface && iNeedInject.IsAssignableFrom(t) && t!=iNeedInject && t!=iTransentInject && t!=iScopeInject && t!= iSingletonInject).ToArray();
foreach (Type interType in interTypes)
{
Type objType= Assembly.Load(assemblyObjName).GetTypes().Where(t =>t.IsClass && interType.IsAssignableFrom(t) && !iNoNeedInject.IsAssignableFrom(t)).SingleOrDefault();
if (objType == null)
{
throw new Exception($"********************当前接口={interType.Name}没有找到对应的实现类********************");
}
IList<Type> inJectTypeList = objType.GetInterfaces().Where(i => i == iTransentInject || i == iScopeInject || i == iSingletonInject).ToList();
if (inJectTypeList.Count != 1)
{
throw new Exception($"********************当前接口={interType.Name}没有找到合适的生命周期类型********************");
}
Type inJectType = inJectTypeList.Single();
string inJectTypeName = inJectType.Name;
switch (inJectTypeName)
{
case "ITransentInject": services.AddTransient(interType, objType); break;
case "IScopeInject": services.AddScoped(interType, objType); break;
case "ISingleTonInject": services.AddSingleton(interType, objType); break;
default: throw new Exception($"********************当前接={interType.Name}没有指定注入实例的生命周期********************");break;
}
}
}
}
***********************************************
在Startup的ConfigureServices方法中调用批量依赖注入的方法:
//获取当前程序集名
string currentAssemblyName = Assembly.GetExecutingAssembly().GetName().Name;
IDictionary<string, string> assemblyNames = new Dictionary<string, string>();
assemblyNames.Add(currentAssemblyName, currentAssemblyName);
//批量注入指定程序集中服务
BatchInjectService(assemblyNames, services);
(7)、在模板控制器中调用调用依赖注入的对象
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace IocPrictic.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
private ISay _ISay;
public ValuesController(ISay isay)
{
this._ISay = isay;
}
// GET api/values
[HttpGet]
public ActionResult<string> Get()
{
string sayResult= this._ISay.Say();
return sayResult;
}
}
}
DotNetCore依赖注入实现批量注入的更多相关文章
- 在ASP.NET Core中实现自动注入、批量注入
我们在使用AddScoped.AddTransient.AddSingleton这类方法的时候很是麻烦.我们每增加一个接口以及其实现的时候,是不是需要在这里硬编码注册一行代码呢?项目小还好,但当我们的 ...
- .net core批量注入实现类
1.获取实现类程序集方法 public class RuntimeHelper { //通过程序集的名称加载程序集 public static Assembly GetAssemblyByName(s ...
- .netcore之DI批量注入(支持泛型) - xms
一旦系统内模块比较多,按DI标准方法去逐个硬敲AddScoped/AddSingleton/AddTransient缺乏灵活性且效率低下,所以批量注入提供了很大的便捷性,特别是对于泛型的服务类,下面介 ...
- Asp.NetCore3.1版本的CodeFirst与经典的三层架构与AutoFac批量注入
Core3.1 CodeFirst与AutoFac批量注入(最下面附GitHub完整 Demo,由于上传网速较慢,这里就直接压缩打包上传了) ===Core3.1 CodeFirst 数据库为远程阿里 ...
- 从我做起[原生DI实现模块化和批量注入].Net Core 之一
实现模块化注册 .Net Core实现模块化批量注入 我将新建一个项目从头开始项目名称Sukt.Core. 该项目分层如下: Sukt.Core.API 为前端提供APi接口(里面尽量不存在业务逻辑, ...
- .NET 使用自带 DI 批量注入服务(Service)和 后台服务(BackgroundService)
今天教大家如何在asp .net core 和 .net 控制台程序中 批量注入服务和 BackgroundService 后台服务 在默认的 .net 项目中如果我们注入一个服务或者后台服务,常规的 ...
- spring依赖注入之构造函数注入,set方法注入
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.spr ...
- Spring 依赖注入中 Field 注入的有害性
大致分为:Field 注入.构造注入.setter 注入 其中 Field 注入被认为有害的: 1. 违反了单一原则 当一个 class 中有多个依赖时,如果仅仅使用 Field 注入,则看不出有很多 ...
- Spring 依赖注入(基本注入和自动适配注入)
Spring 依赖注入 Spring框架的核心功能之一就是通过依赖注入的方式来管理Bean之间的依赖关系. 属性注入 构造注入 内部注入 自动装配 1.属性注入 IService: public in ...
随机推荐
- Python 反射机制
Python的反射机制 Python的反射机制,就是反射就是通过字符串的形式,导入模块:通过字符串的形式,去模块寻找指定函数,并执行.利用字符串的形式去对象(模块)中操作(查找/获取/删除/添加)成员 ...
- 【UI测试】--帮助设施
- Alpha 冲刺 (3/10)
队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 协助后端界面的开发 搭建项目运行的服务器环境 ...
- NOIP2017普及组T2题解
还是神奇的链接 上面依然是题目. 这道题依然很简单,比起2015年的普及组t2好像还是更水一些. 不过这道题能讲的比第一题多. 我们一起来看一下吧! 这一题,我们首先将书的编号全部读入,存在一个数组里 ...
- 求先序排列(NOIP2001&NOIP水题测试(2017082301))
题目链接:求先序排列 这道题讲白了,就是数的构造,然后遍历. 思路大致是这样: 我们先通过后序遍历,找到当前区间的根,然后在中序遍历中找到根对应的下标,然后就可以分出左右子树,建立当前根与左右子树根的 ...
- GameObject.SendMessage
Message相关有3条指令: 要接收消息的GameObject.SendMessage ("函数名",参数,SendMessageOptions) //自身和父Objec ...
- python中的函数嵌套
一.函数嵌套 1.只要遇到了()就是函数的调用.如果没有就不是函数的调用 2.函数的执行顺序 遵循空间作用域,遇到调用才执行 def outer(): def inner(): print(" ...
- IPython:一种交互式计算和开发环境(魔术命令,快捷键)
%run命令 在IPython会话环境中,所有文件都可以通过%run命令当做Python程序来运行. 假设在ipython_script_test.py中存放了一段简单的脚本,如下所示: def f( ...
- Codeforces Round #543 (Div. 2)B,C
https://codeforces.com/contest/1121 B 题意 给你n(<=1000)个数ai,找出最多对和相等的数,每个数只能用一次,且每个数保证各不相同 题解 重点:每个数 ...
- gj13 asyncio并发编程
13.1 事件循环 asyncio 包含各种特定系统实现的模块化事件循环 传输和协议抽象 对TCP.UDP.SSL.子进程.延时调用以及其他的具体支持 模仿futures模块但适用于事件循环使用的Fu ...