当前位置: 移动技术网 > IT编程>开发语言>.net > DotNetCore依赖注入实现批量注入

DotNetCore依赖注入实现批量注入

2019年04月10日  | 移动技术网IT编程  | 我要评论

张开围,saomaomi,n0446

文章转载自平娃子(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;
        }
    }
}

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网