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)所用的默认组织结构开始成为你的负累.你可以使用两种简单的技术来更新组织方法并及时 ...
随机推荐
- 人脸识别Demo
★.本实例使用百度智能云-人工智能-人脸识别API实现. ★.楼下安装了刷脸进门.闲暇时无聊写了个Demo 主界面显示如下图: 本实例,包括了所有人脸识别API的调用. 1. 创建楼号,对应API中创 ...
- python+unittest框架第六天unittest之优化测试报告
今天的内容主要是,用第三方的HTMLRUNner 第三方的报告来优化之前第五天批量执行案例的测试报告.案例的部分看第五天的批量执行笔记~ HTMLRUNner他可以生成更美观的测试报告,基于前辈造的车 ...
- 设计模式(C#)——08组合模式
推荐阅读: 我的CSDN 我的博客园 QQ群:704621321 游戏通常包含许多视图.主视图中显示角色.有一个子视图,显示玩家的积分.有一个子视图,显示游戏中剩下的时间. ...
- 分布式日志收集系统 —— Flume
一.Flume简介 Apache Flume 是一个分布式,高可用的数据收集系统.它可以从不同的数据源收集数据,经过聚合后发送到存储系统中,通常用于日志数据的收集.Flume 分为 NG 和 OG ( ...
- MSIL实用指南-创建对象
创建对象用Newobj指令,它的操作是创建一个新的对象或值类型,并将对象引用的新实例到计算堆栈上.格式是Newobj <构造函数>实例: ilGenerator.Emit(OpCodes. ...
- C# 本地xml文件进行增删改查
项目添加XML文件:FaceXml.xml,并复制到输出目录 FaceXml.xml <?xml version="1.0" encoding="utf-8&quo ...
- Dart语法学习
Dart语法学习 目录 参考资料 语言特性 关键字 变量与常量 数据类型 运算符 operators 控制流程语句 异常 Exceptions 函数 Function 类 Class 类-方法 类-抽 ...
- 特殊字符替换 > < " ' &
function toTXT(str){ var RexStr = /\<|\>|\"|\'|\&/g str = str.replace ...
- 【selenium】- 自动化测试必备工具FireBug&FirePath
本文由小编根据慕课网视频亲自整理,转载请注明出处和作者. 1. FireBug FireBug的安装: 如果使用Firefox浏览器的话,推荐使用较低版本,比如27-32.否则会报错. 点击右上角的菜 ...
- SDU暑期集训排位(8)
A. A Giveaway 签到 B. Game of XOR 做法 dp[G][L][R]表示在倒数第G代,左边的数是L,右边的数是R,下面共有多少个0和1 区间和转换成两次前缀和和一次单点查询 利 ...