VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > c#编程 >
  • C# 当前项目自动服务DI类

思路

我发现 .NET Core WebAPi项目有一个与Springboot的不同之处,就是Springboot项目有自动装配机制,他可以将在src下面与启动类在同一级包目录下的类进行扫描注册

而之前我了解到Springboot的自动装配机制本质上也就是通过扫描对应包,然后进行通过它自身进行服务注册,我虽然写不出那么牛掰的东西,但是我也打算大致仿照一下

步骤如下:

  1. 准备几个装饰类Server、Config等
  2. 扫描当前程序集以及引用程序集被改装饰(注解)描述了的类和接口
  3. 这里要注意注册的顺序,注册的顺序如果出错,就会爆出异常(本人已经经历过)
  4. 同时还需要注意,我们读取配置注册配置类必须是在最前的,因为配置加载最好是在程序启动前全部加载完(不过想想也有懒加载的情况,这里我没有难么多考虑)

代码实现

我这里加载文件配置的代码和注册类的代码写到了一起,有点耦合,大家看可用适当的做拆分,OK希望我的这个小工具类可用帮助到大家,如果大家有更好的想法,希望写出来


 
using gobangBack.Annotation;
 
using System;
 
using System.Reflection;
 
 
 
namespace gobangBack.Utils
 
{
 
// 这个扩展方法仅仅对于本项目
 
/// <summary>
 
/// 步骤:
 
/// 1.对于当前项目的Service目录下的所有带有Service结尾的类型进行父子关系判断
 
/// 2.进行服务类型和实现类型的一次性注入
 
/// </summary>
 
public static class ServiceAutoDI
 
{
 
 
 
public static readonly Queue<Type> RegisterQueue = new Queue<Type>();
 
 
 
 
 
public static void AutoAllDI(this IServiceCollection service) {
 
AutoServerDIFromService(service);
 
}
 
 
 
 
 
// 1.自动注册服务类
 
public static void AutoServerDIFromService(this IServiceCollection service)
 
{
 
 
 
// 1.获取当前程序集中有被Server修饰过的所有的类(并且不能是抽象类)
 
var classTypes = AppDomain.CurrentDomain.GetAssemblies()
 
.SelectMany(assembly => assembly.GetTypes())
 
.Where(type => type.IsClass && !type.IsAbstract)
 
.Where(type => Attribute.IsDefined(type, typeof(Server)))
 
.ToList();
 
// 2.获得当前程序集中被Server修饰过的所有接口
 
var interfaceTypes = AppDomain.CurrentDomain.GetAssemblies()
 
.SelectMany(assembly => assembly.GetTypes())
 
.Where(type => type.IsInterface)
 
.Where(type => Attribute.IsDefined(type, typeof(Server)))
 
.ToList();
 
// 3.获取当前程序集中被Config修饰过的配置类
 
var configClassTypes = AppDomain.CurrentDomain.GetAssemblies()
 
.SelectMany(assembly => assembly.GetTypes())
 
.Where(type => type.IsClass && !type.IsAbstract)
 
.Where(type => Attribute.IsDefined(type, typeof(Config)))
 
.ToList();
 
 
 
 
 
 
 
// 3.判断类型的构造方法中是否有被Server修饰的接口或者是被Config修饰的类
 
// 3.2获取到所有Server修饰类的构造函数中的所有参数
 
var quoteInterface = classTypes
 
.SelectMany(classType => classType.GetConstructors())
 
.SelectMany(constructor => constructor.GetParameters())
 
// 4.2 判断参数中是否有interfaceTypes的值,如果有,就将其找出放入注入队列中
 
.Where(param => interfaceTypes.Contains(param.ParameterType))
 
.Select(param => param.ParameterType).ToList();
 
 
 
foreach (var interfaceType in quoteInterface)
 
{
 
RegisterQueue.Enqueue(interfaceType);
 
interfaceTypes.Remove(interfaceType);
 
}
 
 
 
// 5.进行配置读取
 
 
 
// 5.1.先加载好配置文件
 
var configuration = new ConfigurationBuilder()
 
.AddJsonFile("appsettings.json")
 
.Build();
 
 
 
// 5.2.进行配置文件的读取,配置的名称必须和类名一致
 
 
 
configClassTypes.ForEach(config =>
 
{
 
// 1.获取到配置类结尾的部分
 
string configName = config.FullName.Substring(config.FullName.LastIndexOf(".")+1);
 
// 2.将配置类的配置添加到容器中
 
// 2.1.获取到OptionsConfigurationServiceCollectionExtensions类中名称为Configure参数为IServiceCollection,IConfiguration的方法
 
// 2.2.讲它的泛型类型设置config类型
 
MethodInfo configureMethod = typeof(OptionsConfigurationServiceCollectionExtensions)
 
.GetMethod("Configure", new Type[] { typeof(IServiceCollection), typeof(IConfiguration) })
 
.MakeGenericMethod(config);
 
// 3.读取配置文件中的名称为对应名称的部分,进行加载
 
configureMethod.Invoke(null, new object[] { service, configuration.GetSection(configName) });
 
 
 
// 4.注册配置类
 
service.AddScoped(config);
 
});
 
 
 
// 6.优先注册在队列中的接口
 
var prioityInterface = RegisterQueue.ToArray();
 
 
 
foreach(var interfaceType in prioityInterface)
 
{
 
var implenmentTypes = classTypes.Where(classType => classType.IsAssignableTo(interfaceType))
 
.ToList();
 
implenmentTypes.ForEach(type =>
 
{
 
service.AddScoped(interfaceType, type);
 
});
 
}
 
 
 
// 7.注册其它的接口类型
 
foreach(var interfaceType in interfaceTypes)
 
{
 
var implenmentTypes = classTypes.Where(classType => classType.IsAssignableTo(interfaceType))
 
.ToList();
 
implenmentTypes.ForEach(type =>
 
{
 
service.AddScoped(interfaceType, type);
 
});
 
}
 
}
 
 
 
}
 
}
 
 
 

本文作者:treasureYuki

本文链接:https://www.cnblogs.com/trueasureyuki/p/17826400.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。



相关教程