asp.net core mvc 之 DynamicApi

编程入门 行业动态 更新时间:2024-10-28 12:28:19

asp.<a href=https://www.elefans.com/category/jswz/34/1770819.html style=net core mvc 之 DynamicApi"/>

asp.net core mvc 之 DynamicApi

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

  由于之前移植了一个c#版本的spring cloud feign客户端(),所以想弄个配套的服务端动态接口,实现服务即接口的功能.虽然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);}}

 

项目地址 : .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 parameterNamefor (int i = 0; i < parameters.Length; i++){methodBuilder.DefineParameter(i + 1, ParameterAttributes.None, parameters[i].Name);}#endregiontypeBuilder.DefineMethodOverride(methodBuilder, method);ILGenerator iLGenerator = methodBuilder.GetILGenerator();iLGenerator.Emit(OpCodes.Ldarg_0); // this
            iLGenerator.Emit(OpCodes.Ldfld, interfaceInstanceFieldBuilder);for (int i = 0; i < parameterTypes.Length; i++){iLGenerator.Emit(OpCodes.Ldarg_S, i + 1);}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>();}

 

 

 

 

大功告成

 

转载于:.html

更多推荐

asp.net core mvc 之 DynamicApi

本文发布于:2024-02-17 12:48:06,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1694088.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:net   asp   core   DynamicApi   mvc

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!