文章转载自平娃子(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依赖注入实现批量注入的更多相关文章

  1. 在ASP.NET Core中实现自动注入、批量注入

    我们在使用AddScoped.AddTransient.AddSingleton这类方法的时候很是麻烦.我们每增加一个接口以及其实现的时候,是不是需要在这里硬编码注册一行代码呢?项目小还好,但当我们的 ...

  2. .net core批量注入实现类

    1.获取实现类程序集方法 public class RuntimeHelper { //通过程序集的名称加载程序集 public static Assembly GetAssemblyByName(s ...

  3. .netcore之DI批量注入(支持泛型) - xms

    一旦系统内模块比较多,按DI标准方法去逐个硬敲AddScoped/AddSingleton/AddTransient缺乏灵活性且效率低下,所以批量注入提供了很大的便捷性,特别是对于泛型的服务类,下面介 ...

  4. Asp.NetCore3.1版本的CodeFirst与经典的三层架构与AutoFac批量注入

    Core3.1 CodeFirst与AutoFac批量注入(最下面附GitHub完整 Demo,由于上传网速较慢,这里就直接压缩打包上传了) ===Core3.1 CodeFirst 数据库为远程阿里 ...

  5. 从我做起[原生DI实现模块化和批量注入].Net Core 之一

    实现模块化注册 .Net Core实现模块化批量注入 我将新建一个项目从头开始项目名称Sukt.Core. 该项目分层如下: Sukt.Core.API 为前端提供APi接口(里面尽量不存在业务逻辑, ...

  6. .NET 使用自带 DI 批量注入服务(Service)和 后台服务(BackgroundService)

    今天教大家如何在asp .net core 和 .net 控制台程序中 批量注入服务和 BackgroundService 后台服务 在默认的 .net 项目中如果我们注入一个服务或者后台服务,常规的 ...

  7. spring依赖注入之构造函数注入,set方法注入

    <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.spr ...

  8. Spring 依赖注入中 Field 注入的有害性

    大致分为:Field 注入.构造注入.setter 注入 其中 Field 注入被认为有害的: 1. 违反了单一原则 当一个 class 中有多个依赖时,如果仅仅使用 Field 注入,则看不出有很多 ...

  9. Spring 依赖注入(基本注入和自动适配注入)

    Spring 依赖注入 Spring框架的核心功能之一就是通过依赖注入的方式来管理Bean之间的依赖关系. 属性注入 构造注入 内部注入 自动装配 1.属性注入 IService: public in ...

随机推荐

  1. JUC知识点总结图

    转载http://www.jsondream.com/2017/06/12/about-JUC.html

  2. Quartz(强大的定时器)

    1.关于Quartz的配置文件说明 # # Quartz会优先读取项目下我们自定义这个quartz.properties配置文件 否则会去读取quartzjar包下org.quatrz包# 下面的那个 ...

  3. Linux网桥模式配置

    Linux网关模式下将有线LAN和无线LAN共享网段实现局域网内互联: 思路其实很简单:就是将虚拟出一个bridge口,将对应的有线LAN和无线LAN都绑定在这个虚拟bridge口上,并给这个brid ...

  4. MySQL按日、周、月统计数据

    知识关键词:DATE_FORMAT ps:如果时间字段为时间戳则,DATE_FORMAT(from_unixtime(create_time),'%Y-%u') select DATE_FORMAT( ...

  5. GK888CN与Devexpress报表打印标签

    安装海鸥驱动,貌似打几张也会报错 使用打印机自带的gk888t驱动,用gk888t(EPL)打带二纬码时会报错 需要选择Togther, xrLable 运行 CanShrink

  6. struts上传文件报argument type mismatch错误

    报错如下图所示: 报错原因:把String 强行转换成FormFile,所以才会抛出argument type mismatch.经查询:表单(html:form)中enctype="mul ...

  7. php $_SERVER中的一些选项说明

    1, $_SERVER['SCRIPT_FILENAME'] 和 常量 __FILE__的区别(一般情况下两者的显示相同,都是显示文件的绝对路径,包括文件名,显示的起点是 电脑根目录 /) ①,如果在 ...

  8. IntellJ IDEA 2017 激活编译器配置,读取多个配置文件

    1.设置编译器,找到1,点击2 2.输入设置命令:--spring.profiles.active=test,如果是多个文件输入--spring.profiles.active=test,dev 3. ...

  9. 好文推荐系列--------(2)GruntJS——重复乏味的工作总会有人做(反正我不做)

    GruntJS 是基于JavaScript的命令行构建工具,它可以帮助开发者们自动化重复性的工作.你可以把它看成是JavaScript下的Make或者Ant.它可以完成诸如精简.编译.单元测试.lin ...

  10. GIS矢量数据化简:一种改进的道格拉斯-普克算法以及C++实现

    GIS领域的同志都知道,传统的道格拉斯-普克算法都是递归实现.然而有时候递归的层次太深的话会出现栈溢出的情况.在此,介绍一种非递归的算法. 要将递归算法改为非递归算法,一般情况下分为两种场景.第一种是 ...