这段时间闲赋在家,感觉手痒,故想折腾一些东西.

由于之前移植了一个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的更多相关文章

  1. ASP.NET Core MVC/WebAPi 模型绑定探索

    前言 相信一直关注我的园友都知道,我写的博文都没有特别枯燥理论性的东西,主要是当每开启一门新的技术之旅时,刚开始就直接去看底层实现原理,第一会感觉索然无味,第二也不明白到底为何要这样做,所以只有当你用 ...

  2. ASP.NET Core MVC 配置全局路由前缀

    前言 大家好,今天给大家介绍一个 ASP.NET Core MVC 的一个新特性,给全局路由添加统一前缀.严格说其实不算是新特性,不过是Core MVC特有的. 应用背景 不知道大家在做 Web Ap ...

  3. ASP.NET Core MVC 中的 [Controller] 和 [NonController]

    前言 我们知道,在 MVC 应用程序中,有一部分约定的内容.其中关于 Controller 的约定是这样的. 每个 Controller 类的名字以 Controller 结尾,并且放置在 Contr ...

  4. 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 ...

  5. 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 ...

  6. ASP.NET Core 中文文档 第四章 MVC(01)ASP.NET Core MVC 概览

    原文:Overview of ASP.NET Core MVC 作者:Steve Smith 翻译:张海龙(jiechen) 校对:高嵩 ASP.NET Core MVC 是使用模型-视图-控制器(M ...

  7. ASP.NET Core MVC TagHelper实践HighchartsNET快速图表控件-开源

    ASP.NET Core MVC TagHelper最佳实践HighchartsNET快速图表控件支持ASP.NET Core. 曾经在WebForms上写过 HighchartsNET快速图表控件- ...

  8. ASP.NET Core MVC 在linux上的创建及发布

    前言 ASP.NET core转眼都发布半月多了,社区最近也是非常活跃,虽然最近从事python工作,但也一直对.NET念念不忘,看过了园区大神们搭建的Asp.net core项目之后,自己也是跃跃欲 ...

  9. ASP.NET Core - ASP.NET Core MVC 的功能划分

    概述 大型 Web 应用比小型 Web 应用需要更好的组织.在大型应用中,ASP.NET MVC(和 Core MVC)所用的默认组织结构开始成为你的负累.你可以使用两种简单的技术来更新组织方法并及时 ...

随机推荐

  1. 人脸识别Demo

    ★.本实例使用百度智能云-人工智能-人脸识别API实现. ★.楼下安装了刷脸进门.闲暇时无聊写了个Demo 主界面显示如下图: 本实例,包括了所有人脸识别API的调用. 1. 创建楼号,对应API中创 ...

  2. python+unittest框架第六天unittest之优化测试报告

    今天的内容主要是,用第三方的HTMLRUNner 第三方的报告来优化之前第五天批量执行案例的测试报告.案例的部分看第五天的批量执行笔记~ HTMLRUNner他可以生成更美观的测试报告,基于前辈造的车 ...

  3. 设计模式(C#)——08组合模式

    推荐阅读:  我的CSDN  我的博客园  QQ群:704621321       游戏通常包含许多视图.主视图中显示角色.有一个子视图,显示玩家的积分.有一个子视图,显示游戏中剩下的时间.      ...

  4. 分布式日志收集系统 —— Flume

    一.Flume简介 Apache Flume 是一个分布式,高可用的数据收集系统.它可以从不同的数据源收集数据,经过聚合后发送到存储系统中,通常用于日志数据的收集.Flume 分为 NG 和 OG ( ...

  5. MSIL实用指南-创建对象

    创建对象用Newobj指令,它的操作是创建一个新的对象或值类型,并将对象引用的新实例到计算堆栈上.格式是Newobj <构造函数>实例: ilGenerator.Emit(OpCodes. ...

  6. C# 本地xml文件进行增删改查

    项目添加XML文件:FaceXml.xml,并复制到输出目录 FaceXml.xml <?xml version="1.0" encoding="utf-8&quo ...

  7. Dart语法学习

    Dart语法学习 目录 参考资料 语言特性 关键字 变量与常量 数据类型 运算符 operators 控制流程语句 异常 Exceptions 函数 Function 类 Class 类-方法 类-抽 ...

  8. 特殊字符替换 > < " ' &

    function toTXT(str){         var RexStr = /\<|\>|\"|\'|\&/g         str = str.replace ...

  9. 【selenium】- 自动化测试必备工具FireBug&FirePath

    本文由小编根据慕课网视频亲自整理,转载请注明出处和作者. 1. FireBug FireBug的安装: 如果使用Firefox浏览器的话,推荐使用较低版本,比如27-32.否则会报错. 点击右上角的菜 ...

  10. SDU暑期集训排位(8)

    A. A Giveaway 签到 B. Game of XOR 做法 dp[G][L][R]表示在倒数第G代,左边的数是L,右边的数是R,下面共有多少个0和1 区间和转换成两次前缀和和一次单点查询 利 ...