asp.net core mvc 之 DynamicApi
这段时间闲赋在家,感觉手痒,故想折腾一些东西.
由于之前移植了一个c#版本的spring cloud feign客户端(https://github.com/daixinkai/feign.net),所以想弄个配套的服务端动态接口,实现服务即接口的功能.虽然ABP框架内部包含一个功能强大的DynamicWebApi,但是我只是想要一个独立简单的组件,用来实现以下效果:
有一个业务服务 :
public interface ITestService
{
Task<string> GetName(int id);
}
自动生成类似以下的接口
[Route("api/test")]
public class TestController : ControllerBase
{
public TestController(ITestService testService)
{
_testService = testService;
} ITestService _testService; [HttpGet("name/{id}")]
public Task<string> GetName(int id)
{
return _testService.GetName(id);
} }
项目地址 : https://github.com/daixinkai/Microsoft.AspNetCore.Mvc.DynamicApi
-------------------------------------------------------------------------------------------------
首先定义一个DynamicApiAttribute,替代RouteAttribute的功能
[AttributeUsage(AttributeTargets.Interface, AllowMultiple = false, Inherited = true)]
public class DynamicApiAttribute : Attribute, Microsoft.AspNetCore.Mvc.Routing.IRouteTemplateProvider
{
public DynamicApiAttribute() { }
public DynamicApiAttribute(string template)
{
Template = template;
}
public string Template { get; set; }public int? Order { get; set; }
public string Name { get; set; }
}
思路就是查找标记了DynamicApiAttribute特性的接口,生成一个代理类型注册为控制器
1. BuildProxyType: 定义一个 TypeBuilder
先生成一个类型为当前接口类型的字段 :
FieldBuilder interfaceInstanceFieldBuilder = typeBuilder.DefineField("_interfaceInstance", interfaceType, FieldAttributes.Private);
生成构造函数,接收一个当前接口类型的对象,并赋值给上述字段
ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(
MethodAttributes.Public,
CallingConventions.Standard,
new Type[] { interfaceType });
ILGenerator constructorIlGenerator = constructorBuilder.GetILGenerator();
constructorIlGenerator.Emit(OpCodes.Ldarg_0);
constructorIlGenerator.Emit(OpCodes.Ldarg_1);
constructorIlGenerator.Emit(OpCodes.Stfld, interfaceInstanceFieldBuilder);
constructorIlGenerator.Emit(OpCodes.Ret);
查找接口的所有方法,全部生成
foreach (var method in interfaceType.GetMethodsIncludingBaseInterfaces())
{
BuildMethod(typeBuilder, interfaceType, method, interfaceInstanceFieldBuilder);
}
static void BuildMethod(TypeBuilder typeBuilder, Type interfaceType, MethodInfo method, FieldBuilder interfaceInstanceFieldBuilder)
{
MethodAttributes methodAttributes =
MethodAttributes.Public
| MethodAttributes.HideBySig
| MethodAttributes.NewSlot
| MethodAttributes.Virtual
| MethodAttributes.Final;
var parameters = method.GetParameters();
Type[] parameterTypes = parameters.Select(s => s.ParameterType).ToArray();
MethodBuilder methodBuilder = typeBuilder.DefineMethod(method.Name, methodAttributes, CallingConventions.Standard, method.ReturnType, parameterTypes); #region parameterName for (int i = ; i < parameters.Length; i++)
{
methodBuilder.DefineParameter(i + , ParameterAttributes.None, parameters[i].Name);
} #endregion typeBuilder.DefineMethodOverride(methodBuilder, method);
ILGenerator iLGenerator = methodBuilder.GetILGenerator();
iLGenerator.Emit(OpCodes.Ldarg_0); // this
iLGenerator.Emit(OpCodes.Ldfld, interfaceInstanceFieldBuilder);
for (int i = ; i < parameterTypes.Length; i++)
{
iLGenerator.Emit(OpCodes.Ldarg_S, i + );
}
iLGenerator.Emit(OpCodes.Call, method);
iLGenerator.Emit(OpCodes.Ret);
var datas = CustomAttributeData.GetCustomAttributes(method);
foreach (var data in datas)
{
CustomAttributeBuilder customAttributeBuilder = new CustomAttributeBuilder(data.Constructor, data.ConstructorArguments.Select(s => s.Value).ToArray());
methodBuilder.SetCustomAttribute(customAttributeBuilder);
}
}
最后别忘了复制特性
var datas = CustomAttributeData.GetCustomAttributes(interfaceType);
foreach (var data in datas)
{
CustomAttributeBuilder customAttributeBuilder = new CustomAttributeBuilder(data.Constructor, data.ConstructorArguments.Select(s => s.Value).ToArray());
typeBuilder.SetCustomAttribute(customAttributeBuilder);
}
这样代理类型就生成完毕了
2.注册到Mvc框架中
由于默认ControllerFeatureProvider不支持生成的代理类型,需要自定义实现
public class DynamicApiControllerFeatureProvider : ControllerFeatureProvider
{
protected override bool IsController(TypeInfo typeInfo)
{
return typeInfo.IsProxyApi();
}
}
public static IMvcBuilder AddDynamicApi(this IMvcBuilder builder)
{ var feature = new ControllerFeature(); foreach (AssemblyPart assemblyPart in builder.PartManager.ApplicationParts.OfType<AssemblyPart>())
{
foreach (var type in assemblyPart.Types)
{
if (type.IsInterface && type.IsDefinedIncludingBaseInterfaces<DynamicApiAttribute>() && !type.IsDefined(typeof(NonDynamicApiAttribute)) && !type.IsGenericType)
{
feature.Controllers.Add(DynamicApiProxy.GetProxyType(type));//feature.Controllers.Add没什么卵用
}
}
} builder.AddApplicationPart(DynamicApiProxy.DynamicAssembly.AssemblyBuilder); builder.PartManager.FeatureProviders.Add(new DynamicApiControllerFeatureProvider()); return builder;
}
这样就完成了,是不是很简单实用! 另外DynamicApi支持Mvc内置的Filter
3. 测试一下
[DynamicApi("api/testService")]
public interface ITestService
{
//[Microsoft.AspNetCore.Authorization.Authorize]
[HttpGet("name/{id}")]
Task<string> GetName(int id);
} public class TestService : ITestService
{
public Task<string> GetName(int id)
{
return Task.FromResult("Name" + id);
}
}
最后别忘了注入服务
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2).AddDynamicApi();
services.AddTransient<ITestService, TestService>();
}
大功告成
asp.net core mvc 之 DynamicApi的更多相关文章
- ASP.NET Core MVC/WebAPi 模型绑定探索
前言 相信一直关注我的园友都知道,我写的博文都没有特别枯燥理论性的东西,主要是当每开启一门新的技术之旅时,刚开始就直接去看底层实现原理,第一会感觉索然无味,第二也不明白到底为何要这样做,所以只有当你用 ...
- ASP.NET Core MVC 配置全局路由前缀
前言 大家好,今天给大家介绍一个 ASP.NET Core MVC 的一个新特性,给全局路由添加统一前缀.严格说其实不算是新特性,不过是Core MVC特有的. 应用背景 不知道大家在做 Web Ap ...
- ASP.NET Core MVC 中的 [Controller] 和 [NonController]
前言 我们知道,在 MVC 应用程序中,有一部分约定的内容.其中关于 Controller 的约定是这样的. 每个 Controller 类的名字以 Controller 结尾,并且放置在 Contr ...
- ASP.NET Core 中文文档 第二章 指南(2)用 Visual Studio 和 ASP.NET Core MVC 创建首个 Web API
原文:Building Your First Web API with ASP.NET Core MVC and Visual Studio 作者:Mike Wasson 和 Rick Anderso ...
- ASP.NET Core 中文文档 第二章 指南(4.1)ASP.NET Core MVC 与 Visual Studio 入门
原文:Getting started with ASP.NET Core MVC and Visual Studio 作者:Rick Anderson 翻译:娄宇(Lyrics) 校对:刘怡(Alex ...
- ASP.NET Core 中文文档 第四章 MVC(01)ASP.NET Core MVC 概览
原文:Overview of ASP.NET Core MVC 作者:Steve Smith 翻译:张海龙(jiechen) 校对:高嵩 ASP.NET Core MVC 是使用模型-视图-控制器(M ...
- ASP.NET Core MVC TagHelper实践HighchartsNET快速图表控件-开源
ASP.NET Core MVC TagHelper最佳实践HighchartsNET快速图表控件支持ASP.NET Core. 曾经在WebForms上写过 HighchartsNET快速图表控件- ...
- ASP.NET Core MVC 在linux上的创建及发布
前言 ASP.NET core转眼都发布半月多了,社区最近也是非常活跃,虽然最近从事python工作,但也一直对.NET念念不忘,看过了园区大神们搭建的Asp.net core项目之后,自己也是跃跃欲 ...
- ASP.NET Core - ASP.NET Core MVC 的功能划分
概述 大型 Web 应用比小型 Web 应用需要更好的组织.在大型应用中,ASP.NET MVC(和 Core MVC)所用的默认组织结构开始成为你的负累.你可以使用两种简单的技术来更新组织方法并及时 ...
随机推荐
- Linux下手动安装MySQL5.7
1.下载tar包,这里使用wget从官网下载 https://dev.mysql.com/downloads/mysql/ 2.将mysql安装到/usr/local/mysql下 # 解压 tar ...
- CentOS7下使用SonatypeNexus3搭建Docker私有仓库
前置条件:安装docker(如果机器上没有安装的话) //安装一些必要的系统工具: sudo yum install -y yum-utils device-mapper-persistent-dat ...
- Java NIO 下
内存映射文件 JAVA处理大文件,一般用BufferedReader,BufferedInputStream这类带缓冲的IO类,不过如果文件超大的话,更快的方式是采用MappedByteBuffer. ...
- HZNU 2019 Summer training 6 -CodeForces - 622
A - Infinite Sequence CodeForces - 622A 题目大意:给你一个这样的数列1,1,2,1,2,3,1,2,3,4,1,2,3,4,5....就是从1~n排列(n++ ...
- HDU 6430 Problem E. TeaTree(虚树)
Problem E. TeaTree Problem Description Recently, TeaTree acquire new knoledge gcd (Greatest Common D ...
- poj 2649 Factovisors 对n!进行因数分解
Factovisors Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 4431 Accepted: 1086 Descr ...
- x86_64 Linux 运行时栈的字节对齐
前言 C语言的过程调用机制(即函数之间的调用)的一个关键特性(起始大多数编程语言也是如此)都是使用了栈数据结构提供的后进先出的内存管理原则.每一个函数的栈空间被称为栈帧,一个栈帧上包含了保存的寄存器. ...
- 【Offer】[61] 【扑克牌中的顺子】
题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的.2~10 为数字本身,A为1, J为11, Q为12,K为13,而大 ...
- Vue之render渲染函数和JSX的应用
一.模板缺陷 模板的最大特点是扩展难度大,不易扩展.可能会造成逻辑冗余 <Level :type="1">哈哈</Level> <Level :typ ...
- 聚焦Python分布式爬虫必学框架Scrapy 打造搜索引擎视频教程
下载链接:https://www.yinxiangit.com/595.html 目录: 第1章 课程介绍介绍课程目标.通过课程能学习到的内容.和系统开发前需要具备的知识 第2章 windows下搭建 ...