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

1. 先来个dll助手

无外部依赖,可直接复用

 using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.Loader; namespace Xms.Infrastructure.Utility
{
public class AssemblyHelper
{
public static List<Assembly> GetAssemblies(string searchPattern = "")
{
List<Assembly> assemblies = new List<Assembly>();
if (searchPattern.HasValue())
{
DirectoryInfo root = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);
foreach (FileInfo f in root.GetFiles(searchPattern))
{
assemblies.Add(AssemblyLoadContext.Default.LoadFromAssemblyPath(f.FullName));
}
}
else
{
assemblies.AddRange(AppDomain.CurrentDomain.GetAssemblies());
}
return assemblies;
} public static List<Type> GetClassOfType(Type assignTypeFrom, string searchPattern = "")
{
var assemblies = GetAssemblies(searchPattern);
var result = new List<Type>();
try
{
foreach (var a in assemblies)
{
Type[] types = a.GetTypes(); if (types == null)
{
continue;
} foreach (var t in types)
{
if (!assignTypeFrom.IsAssignableFrom(t) && (!assignTypeFrom.IsGenericTypeDefinition || !DoesTypeImplementOpenGeneric(t, assignTypeFrom)))
{
continue;
} if (t.IsInterface)
{
continue;
} if (t.IsAbstract)
{
continue;
} result.Add(t);
}
}
}
catch (ReflectionTypeLoadException ex)
{
var msg = string.Empty;
foreach (var e in ex.LoaderExceptions)
{
msg += e.Message + Environment.NewLine;
} var fail = new Exception(msg, ex);
Debug.WriteLine(fail.Message, fail); throw fail;
} return result;
} public static bool DoesTypeImplementOpenGeneric(Type type, Type openGeneric)
{
try
{
var genericTypeDefinition = openGeneric.GetGenericTypeDefinition();
foreach (var implementedInterface in type.FindInterfaces((objType, objCriteria) => true, null))
{
if (!implementedInterface.IsGenericType)
{
continue;
} var isMatch = genericTypeDefinition.IsAssignableFrom(implementedInterface.GetGenericTypeDefinition());
return isMatch;
} return false;
}
catch
{
return false;
}
}
}
}

2. 服务自动注册接口

用于每个模块注册自己的服务,达到模块的高度自治的目的

 using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; namespace Xms.Infrastructure.Inject
{
/// <summary>
/// 服务自动注册接口
/// </summary>
public interface IServiceRegistrar
{
void Add(IServiceCollection services, IConfiguration configuration); int Order { get; }
}
}

3. DI服务扩展方法

 using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using Xms.Infrastructure.Inject;
using Xms.Infrastructure.Utility; namespace Xms.Core
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection RegisterAll(this IServiceCollection services, IConfiguration configuration)
{
var types = AssemblyHelper.GetClassOfType(typeof(IServiceRegistrar), "Xms.*.dll");
foreach (var t in types)
{
var instance = (IServiceRegistrar)Activator.CreateInstance(t);
instance.Add(services, configuration);
}
return services;
} public static IServiceCollection RegisterScope<TService>(this IServiceCollection services)
{
var serviceType = typeof(TService);
return Register(services, serviceType, ServiceLifetime.Scoped);
} public static IServiceCollection RegisterScope(this IServiceCollection services, Type serviceType)
{
return Register(services, serviceType, ServiceLifetime.Scoped);
} public static IServiceCollection Register(this IServiceCollection services, Type serviceType, ServiceLifetime serviceLifetime)
{
var implementTypes = AssemblyHelper.GetClassOfType(serviceType, "Xms.*.dll");
if (serviceType.IsGenericType)
{
foreach (var impl in implementTypes)
{
var it = impl.FindInterfaces((type, criteria) =>
{
var isMatch = type.IsGenericType && ((Type)criteria).IsAssignableFrom(type.GetGenericTypeDefinition());
return isMatch;
}, serviceType);
foreach (var i in it)
{
services.Add(new ServiceDescriptor(i, impl, serviceLifetime));
}
}
}
else
{
foreach (var impl in implementTypes)
{
services.Add(new ServiceDescriptor(serviceType, impl, serviceLifetime));
}
}
return services;
}
}
}

4. 使用示例

比如下面的一个事件发布服务类,多个消费者服务类,实现了消费者的动态注册,大大提高了系统的灵活性、扩展性

     /// <summary>
/// 事件模块服务注册
/// </summary>
public class ServiceRegistrar : IServiceRegistrar
{
public int Order => ; public void Add(IServiceCollection services, IConfiguration configuration)
{
//event publisher
services.AddScoped<Event.Abstractions.IEventPublisher, Event.EventPublisher>();
//event consumers
services.RegisterScope(typeof(Event.Abstractions.IConsumer<>));
}
}

.netcore之DI批量注入(支持泛型) - xms的更多相关文章

  1. .netcore利用DI实现订阅者模式 - xms

    结合DI,实现发布者与订阅者的解耦,属于本次事务的对象主体不应定义为订阅者,因为订阅者不应与发布者产生任何关联 一.发布者订阅者模式 发布者发出一个事件主题,一个或多个订阅者接收这个事件,中间通过事件 ...

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

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

  3. 封装了一些sqlsugar的常用方法 用来动态切换数据库和依赖注入 支持泛型

    接口: /// <summary> /// 数据库操作 /// </summary> public interface IDAL_Services { /// <summ ...

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

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

  5. Spring:(二)DI依赖注入方式

    DI 依赖注入 DI(Dependency Injection)依赖注入,说简单一点就将类里面的属性在创建类的过程中给属性赋值,即将对象依赖属性(简单值,集合,对象)通过配置设值给该对象. 属性注入的 ...

  6. DotNetCore依赖注入实现批量注入

    文章转载自平娃子(QQ:273206491):http://os.pingwazi.cn/resource/batchinjectservice 一.依赖注入 通过依赖注入,可以实现接口与实现类的松耦 ...

  7. AutoFac IoC DI 依赖注入

    AutoFac IoC DI 依赖注入 记录点点滴滴知识,为了更好的服务后来者! 一.为什么使用AutoFac? 之前介绍了Unity和Ninject两个IOC容器,但是发现园子里用AutoFac的貌 ...

  8. Spring-初识Spring框架-IOC控制反转(DI依赖注入)

    ---恢复内容开始--- IOC :控制反转 (DI:依赖注入)使用ioc模式开发 实体类必须有无参构造方法1.搭建Spring环境下载jarhttp://maven.springframework. ...

  9. .netCore2.0 程序集DI依赖注入

    传统的依赖注入确实简单,但是随着项目的扩展随之而来的问题又来了,因为传统的注入是单个类和接口注入的,加入项目的接口和类增加到了上百个的话,就需要在Startup.cs中复制注入上百次,虽然能解决问题, ...

随机推荐

  1. LeetCode初级算法--数组01:只出现一次的数字

    LeetCode初级算法--数组01:只出现一次的数字 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn. ...

  2. DG常用运维命令及常见问题解决

    DG常见运维命令及常见问题解决方法 l> DG库启动.关闭标准操作Dataguard关闭1).先取消日志应用alter database recover managed standby data ...

  3. redis缓存+session 实现单点登录

    一.单点登录介绍 单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一.SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系 ...

  4. 生产环境中的kubernetes 优先级与抢占

    kubernetes 中的抢占功能是调度器比较重要的feature,但是真正使用起来还是比较危险,否则很容易把低优先级的pod给无辜kill.为了提高GPU集群的资源利用率,决定勇于尝试一番该feat ...

  5. javascript语言学习

    本课将和大家一起学习简单的js dom 操作,涵盖DOM API以及JQuery的方法. 相关简介             JavaScript一种直译式脚本语言,是一种动态类型.弱类型.基于原型的语 ...

  6. luogu P3936 Coloring

    [返回模拟退火略解] 题目描述 在一个 n×mn\times mn×m 的矩阵中,每个点都染了一种颜色(只能是 [1,c][1,c][1,c] 中的一种),求一种方案,使得相邻异色点对数最小. Sol ...

  7. java学习3-流程控制与数组

    1.顺序结构 2.分支结构 3.循环结构 4.控制循环结构 break continue return 5.数组

  8. linux 中more、less 和 most 的区别

    如果你是一个 Linux 方面的新手,你可能会在 more.less.most 这三个命令行工具之间产生疑惑.在本文当中,我会对这三个命令行工具进行对比,以及展示它们各自在 Linux 中的一些使用例 ...

  9. 百万年薪python之路 -- 函数初始

    1.函数 1.1 认识函数 定义一个事情或者是功能,等到需要的时候直接去用就好了.那么这里定义东西就是一个函数 函数:对代码块和功能的封装和定义 函数的好处: 减少代码的重复性 代码可读性高 将功能进 ...

  10. ggstatsplot绘图|统计+可视化,学术科研神器

    本文首发于“生信补给站”公众号,https://mp.weixin.qq.com/s/zdSit97SOEpbnR18ARzixw 更多关于R语言,ggplot2绘图,生信分析的内容,敬请关注小号. ...