【懒人有道】在asp.net core中实现程序集注入
前言
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//services.RegisterAssembly("IServices");
services.AddSingleton<IUserService, UserService>();
// Add framework services.
services.AddMvc();
services.AddMvcCore()
.AddApiExplorer();
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new Info()
{
Title = "Swagger测试",
Version = "v1",
Description = "Swagger测试RESTful API ",
TermsOfService = "None",
Contact = new Contact
{
Name = "来来吹牛逼",
Email = "xxoo123@outlook.com"
},
});
//设置xml注释文档,注意名称一定要与项目名称相同
var filePath = Path.Combine(PlatformServices.Default.Application.ApplicationBasePath, "WebApi.xml");
options.IncludeXmlComments(filePath);
});
}
但是,随着公司业务的扩大,系统项目的功能模块急剧扩张,新增了不下百个或者千个Repository和Service(有点夸张了...),这时候如此单纯滴注入就有点操蛋了。
打懒主意
试试就试试
- UserService --> IUserService
- UserRepository --> IUserRepository
- ......
- ClassName --> IClassName
好了,我们下面开始编码:
/// <summary>
/// IServiceCollection扩展
/// </summary>
public static class ServiceExtension
{
/// <summary>
/// 用DI批量注入接口程序集中对应的实现类。
/// <para>
/// 需要注意的是,这里有如下约定:
/// IUserService --> UserService, IUserRepository --> UserRepository.
/// </para>
/// </summary>
/// <param name="service"></param>
/// <param name="interfaceAssemblyName">接口程序集的名称(不包含文件扩展名)</param>
/// <returns></returns>
public static IServiceCollection RegisterAssembly(this IServiceCollection service, string interfaceAssemblyName)
{
if (service == null)
throw new ArgumentNullException(nameof(service));
if (string.IsNullOrEmpty(interfaceAssemblyName))
throw new ArgumentNullException(nameof(interfaceAssemblyName)); var assembly = RuntimeHelper.GetAssembly(interfaceAssemblyName);
if (assembly == null)
{
throw new DllNotFoundException($"the dll \"{interfaceAssemblyName}\" not be found");
} //过滤掉非接口及泛型接口
var types = assembly.GetTypes().Where(t => t.GetTypeInfo().IsInterface && !t.GetTypeInfo().IsGenericType); foreach (var type in types)
{
var implementTypeName = type.Name.Substring();
var implementType = RuntimeHelper.GetImplementType(implementTypeName, type);
if (implementType != null)
service.AddSingleton(type, implementType);
}
return service;
} /// <summary>
/// 用DI批量注入接口程序集中对应的实现类。
/// </summary>
/// <param name="service"></param>
/// <param name="interfaceAssemblyName">接口程序集的名称(不包含文件扩展名)</param>
/// <param name="implementAssemblyName">实现程序集的名称(不包含文件扩展名)</param>
/// <returns></returns>
public static IServiceCollection RegisterAssembly(this IServiceCollection service, string interfaceAssemblyName, string implementAssemblyName)
{
if (service == null)
throw new ArgumentNullException(nameof(service));
if(string.IsNullOrEmpty(interfaceAssemblyName))
throw new ArgumentNullException(nameof(interfaceAssemblyName));
if (string.IsNullOrEmpty(implementAssemblyName))
throw new ArgumentNullException(nameof(implementAssemblyName)); var interfaceAssembly = RuntimeHelper.GetAssembly(interfaceAssemblyName);
if (interfaceAssembly == null)
{
throw new DllNotFoundException($"the dll \"{interfaceAssemblyName}\" not be found");
} var implementAssembly = RuntimeHelper.GetAssembly(implementAssemblyName);
if (implementAssembly == null)
{
throw new DllNotFoundException($"the dll \"{implementAssemblyName}\" not be found");
} //过滤掉非接口及泛型接口
var types = interfaceAssembly.GetTypes().Where(t => t.GetTypeInfo().IsInterface && !t.GetTypeInfo().IsGenericType); foreach (var type in types)
{
//过滤掉抽象类、泛型类以及非class
var implementType = implementAssembly.DefinedTypes
.FirstOrDefault(t => t.IsClass && !t.IsAbstract && !t.IsGenericType &&
t.GetInterfaces().Any(b => b.Name == type.Name));
if (implementType != null)
{
service.AddSingleton(type, implementType.AsType());
}
} return service;
}
}
附上RuntimeHelper.cs的代码:
public class RuntimeHelper
{
/// <summary>
/// 获取项目程序集,排除所有的系统程序集(Microsoft.***、System.***等)、Nuget下载包
/// </summary>
/// <returns></returns>
public static IList<Assembly> GetAllAssemblies()
{
var list = new List<Assembly>();
var deps = DependencyContext.Default;
var libs = deps.CompileLibraries.Where(lib => !lib.Serviceable && lib.Type != "package");//排除所有的系统程序集、Nuget下载包
foreach (var lib in libs)
{
try
{
var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name));
list.Add(assembly);
}
catch (Exception)
{
// ignored
}
}
return list;
} public static Assembly GetAssembly(string assemblyName)
{
return GetAllAssemblies().FirstOrDefault(assembly => assembly.FullName.Contains(assemblyName));
} public static IList<Type> GetAllTypes()
{
var list = new List<Type>();
foreach (var assembly in GetAllAssemblies())
{
var typeInfos = assembly.DefinedTypes;
foreach (var typeInfo in typeInfos)
{
list.Add(typeInfo.AsType());
}
}
return list;
} public static IList<Type> GetTypesByAssembly(string assemblyName)
{
var list = new List<Type>();
var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(assemblyName));
var typeInfos = assembly.DefinedTypes;
foreach (var typeInfo in typeInfos)
{
list.Add(typeInfo.AsType());
}
return list;
} public static Type GetImplementType(string typeName, Type baseInterfaceType)
{
return GetAllTypes().FirstOrDefault(t =>
{
if (t.Name == typeName &&
t.GetTypeInfo().GetInterfaces().Any(b => b.Name == baseInterfaceType.Name))
{
var typeInfo = t.GetTypeInfo();
return typeInfo.IsClass && !typeInfo.IsAbstract && !typeInfo.IsGenericType;
}
return false;
});
}
}
好了,到此就基本完成了,记得在Startup.cs加上:
// This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.RegisterAssembly("IServices"); // Add framework services.
services.AddMvc();
}
总结
【懒人有道】在asp.net core中实现程序集注入的更多相关文章
- C# 嵌入dll 动软代码生成器基础使用 系统缓存全解析 .NET开发中的事务处理大比拼 C#之数据类型学习 【基于EF Core的Code First模式的DotNetCore快速开发框架】完成对DB First代码生成的支持 基于EF Core的Code First模式的DotNetCore快速开发框架 【懒人有道】在asp.net core中实现程序集注入
C# 嵌入dll 在很多时候我们在生成C#exe文件时,如果在工程里调用了dll文件时,那么如果不加以处理的话在生成的exe文件运行时需要连同这个dll一起转移,相比于一个单独干净的exe,这种形 ...
- ASP.NET Core中的依赖注入(1):控制反转(IoC)
ASP.NET Core在启动以及后续针对每个请求的处理过程中的各个环节都需要相应的组件提供相应的服务,为了方便对这些组件进行定制,ASP.NET通过定义接口的方式对它们进行了"标准化&qu ...
- ASP.NET Core中的依赖注入(4): 构造函数的选择与服务生命周期管理
ServiceProvider最终提供的服务实例都是根据对应的ServiceDescriptor创建的,对于一个具体的ServiceDescriptor对象来说,如果它的ImplementationI ...
- ASP.NET Core中的依赖注入(5): ServiceProvider实现揭秘 【总体设计 】
本系列前面的文章我们主要以编程的角度对ASP.NET Core的依赖注入系统进行了详细的介绍,如果读者朋友们对这些内容具有深刻的理解,我相信你们已经可以正确是使用这些与依赖注入相关的API了.如果你还 ...
- ASP.NET Core中的依赖注入(2):依赖注入(DI)
IoC主要体现了这样一种设计思想:通过将一组通用流程的控制从应用转移到框架之中以实现对流程的复用,同时采用"好莱坞原则"是应用程序以被动的方式实现对流程的定制.我们可以采用若干设计 ...
- ASP.NET Core中的依赖注入(3): 服务的注册与提供
在采用了依赖注入的应用中,我们总是直接利用DI容器直接获取所需的服务实例,换句话说,DI容器起到了一个服务提供者的角色,它能够根据我们提供的服务描述信息提供一个可用的服务对象.ASP.NET Core ...
- ASP.NET Core中的依赖注入(5): ServiceProvider实现揭秘 【解读ServiceCallSite 】
通过上一篇的介绍我们应该对实现在ServiceProvider的总体设计有了一个大致的了解,但是我们刻意回避一个重要的话题,即服务实例最终究竟是采用何种方式提供出来的.ServiceProvider最 ...
- ASP.NET Core中的依赖注入(5):ServicePrvider实现揭秘【补充漏掉的细节】
到目前为止,我们定义的ServiceProvider已经实现了基本的服务提供和回收功能,但是依然漏掉了一些必需的细节特性.这些特性包括如何针对IServiceProvider接口提供一个Service ...
- ASP.NET Core 中的依赖注入
目录 什么是依赖注入 ASP .NET Core 中使用依赖注入 注册 使用 释放 替换为其它的 Ioc 容器 参考 什么是依赖注入 软件设计原则中有一个依赖倒置原则(DIP),为了更好的解耦,讲究要 ...
随机推荐
- [转载]python 详解re模块
原文地址:python 详解re模块作者:Rocky 正则表达式的元字符有. ^ $ * ? { [ ] | ( ) .表示任意字符 []用来匹配一个指定的字符类别,所谓的字符类别就是你想匹配的一个字 ...
- 结对编程1-四则运算(基于GUI)
林晓芳201421123092.陈惠201421123096 coding 地址:https://git.coding.net/lianlian/92.96.1.git 一.题目描述 我们在个人作业1 ...
- 团队作业4——第一次项目冲刺(Alpha版本)2017.4.23
1.当天站立式会议照片 本次会议为第一次会议 本次会议在5号公寓1楼召开,本次会议内容: ①:做第一天的简单分工 ②:讨论每个人是否对安排的任务有苦难 ③:规定完成时间是在第二天之前 ④:遇到困难,及 ...
- 201521123008《Java程序设计》第四周学习总结
1.本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 1.包的命名规范 2.面向对象设计:名词/动词 3.类的设计技巧:一定将属性设计为私有priv ...
- 第2周作业-Java基本语法与类库
1. 本周学习总结 答:① 定义流程控制的各种条件式是同以前学习的一样,要善于运用快捷键.(例如`a/t` + `/` ) ② 熟悉输入输出的使用,注意输入的变量类型使用相应的输入类. ③ 数组对象: ...
- 201521123100 《java程序设计》第12周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件相关内容. 2. 书面作业 将Student对象(属性:int id, String name,int age,doubl ...
- 跨站数据请求哪家强——青出于蓝的jsonp
/* * 跨站数据请求哪家强--青出于蓝的jsonp数据格式 * @author gj * @date 2017-09-15 */ 先哲有云"青,取之于蓝,而青于蓝:冰,水为之,而寒于水&q ...
- 如何在mybatis 中使用In操作
如何在mybatis 中使用In操作 假如我们想使用这样一个sql 语句,但是这样的sql语句有IN这样的操作.在我们的mybatis中有相对应的操作 SELECT * FROM product_db ...
- oracle pl/sql 简介
一.pl/sql 是什么pl/sql(procedural language/sql)是oracle在标准的sql语言上的扩展.pl/sql不仅允许嵌入sql语言,还可以定义变量和常量,允许使用条件语 ...
- C#设计模式之四抽象工厂模式(AbstractFactory)【创建型】
一.引言 写了3篇有关设计模式的文章了,大家有了些反馈,说能从中学到一些东西,我感到很欣慰,那就继续努力.今天我要写第四个模式了,该模式叫抽象工厂.上一篇文章我们讲了[工厂方法]模式,它是为了 ...