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;
}
}
}
上一篇: 开机速度慢?加快开机速度的图文方法介绍
下一篇: 区块链技术的原住民 眼见圈外人跑入场