【动态Web API学习(三)】动态方法

1.应用程序模型

ASP.NET Core MVC根据控制器、操作、操作参数、路由和筛选器的结果,定义模型如下:
ApplicationModel、控制器(ControllerModel)、操作(ActionModel)和参数(ParameterModel)。

上一节中只是告诉系统封哪个是控制器,还要为控制器模型初始化值,比如路由、请求方式(post、get)、方法名,才可以真正实现动态Web API。

2.动态方法实现

2.1 添加AutoApplicationModelConvention

在项目Flavor.AutoWebAPICore,添加AutoApplicationModelConvention。
image

2.2 AutoApplicationModelConvention代码

AutoApplicationModelConvention
using System.Text; using Flavor.AutoWebAPICore; using Microsoft.AspNetCore.Mvc.ActionConstraints; using Microsoft.AspNetCore.Mvc.ApplicationModels; namespace Flavor.AutoWebAPICore { /// <summary> /// 自动控制器应用模型 /// </summary> public class AutoApplicationModelConvention : IApplicationModelConvention { /// <summary> /// 控制器移除的后缀 /// </summary> private readonly string _ControllerRemoveSuffix = "AppService"; public void Apply(ApplicationModel application) { //遍历控制器 foreach (var controller in application.Controllers) { var type = controller.ControllerType; //设置控制器名称 if (controller.ControllerName.EndsWith(_ControllerRemoveSuffix)) { controller.ControllerName = controller.ControllerName[..^_ControllerRemoveSuffix.Length]; } //控制器继承于IAutoController if (typeof(IAutoController).IsAssignableFrom(type)) { //设置API对外可见 ConfigureApiExplorer(controller); //设置控制器选择器 ConfigureSelector(controller); } } } /// <summary> /// 设置API对外可见 /// </summary> /// <param name="controller"></param> private static void ConfigureApiExplorer(ControllerModel controller) { if (!controller.ApiExplorer.IsVisible.HasValue) { controller.ApiExplorer.IsVisible = true; } foreach (var action in controller.Actions) { if (!action.ApiExplorer.IsVisible.HasValue) { action.ApiExplorer.IsVisible = true; } } } /// <summary> /// 设置控制器选择器 /// </summary> /// <param name="controller"></param> private void ConfigureSelector(ControllerModel controller) { //移除空的选择器 RemoveEmptySelectors(controller.Selectors); if (controller.Selectors.Any(selector => selector.AttributeRouteModel != null)) { return; } //遍历控制器的方法 foreach (var action in controller.Actions) { //设置方法的选择器 ConfigureSelector(action); } } /// <summary> /// 移除空的选择器 /// </summary> /// <param name="selectors"></param> private static void RemoveEmptySelectors(IList<SelectorModel> selectors) { for (var i = selectors.Count - 1; i >= 0; i--) { var selector = selectors[i]; if (selector.AttributeRouteModel == null && (selector.ActionConstraints == null || selector.ActionConstraints.Count <= 0) && (selector.EndpointMetadata == null || selector.EndpointMetadata.Count <= 0)) { selectors.Remove(selector); } } } /// <summary> /// 设置方法的选择器 /// </summary> /// <param name="action"></param> private void ConfigureSelector(ActionModel action) { RemoveEmptySelectors(action.Selectors); if (action.Selectors.Count <= 0) { //添加选择器 AddServiceSelector(action); } else { //格式化选择器 NormalizeSelectorRoutes(action); } } /// <summary> /// 为方法添加选择器:路由、Http请求方式 /// </summary> /// <param name="action"></param> private void AddServiceSelector(ActionModel action) { var httpMothod = GetHttpMethod(action); var template = new Microsoft.AspNetCore.Mvc.RouteAttribute(GetRouteTemplate(action)); var selector = new SelectorModel { AttributeRouteModel = new AttributeRouteModel(template) }; selector.ActionConstraints.Add(new HttpMethodActionConstraint(new[] { httpMothod })); action.Selectors.Add(selector); } /// <summary> /// 格式化方法选择器:路由、Http请求方式 /// </summary> /// <param name="action"></param> private void NormalizeSelectorRoutes(ActionModel action) { foreach (var selector in action.Selectors) { var httpMothod = GetHttpMethod(action); if (selector.AttributeRouteModel == null) { var template = new Microsoft.AspNetCore.Mvc.RouteAttribute(GetRouteTemplate(action)); selector.AttributeRouteModel = new AttributeRouteModel(template); } if (selector.ActionConstraints.OfType<HttpMethodActionConstraint>().FirstOrDefault()?.HttpMethods?.FirstOrDefault() == null) { selector.ActionConstraints.Add(new HttpMethodActionConstraint(new[] { httpMothod })); } } } /// <summary> /// 获取路由 /// </summary> /// <param name="action"></param> /// <returns></returns> private string GetRouteTemplate(ActionModel action) { //路由 var routeTemplate = new StringBuilder(); // 控制器 var controllerName = action.Controller.ControllerName; if (controllerName.EndsWith(_ControllerRemoveSuffix)) { controllerName = controllerName[0..^_ControllerRemoveSuffix.Length]; } routeTemplate.Append($"/{controllerName}"); // 方法 var actionName = action.ActionName; if (!string.IsNullOrEmpty(actionName)) { routeTemplate.Append($"/{actionName}"); } return routeTemplate.ToString(); } /// <summary> /// 获取请求方式 /// </summary> /// <param name="action"></param> /// <returns></returns> private static string GetHttpMethod(ActionModel action) { var actionName = action.ActionName; if (actionName.StartsWith("Get")) { return "Get"; } else if (actionName.StartsWith("Put")) { return "Put"; } else if (actionName.StartsWith("Delete")) { return "Delete"; } else if (actionName.StartsWith("Options")) { return "Options"; } else if (actionName.StartsWith("Trace")) { return "Trace"; } else if (actionName.StartsWith("Head")) { return "Head"; } else if (actionName.StartsWith("Patch")) { return "Patch"; } return "Post"; } } }

代码说明:
1、AutoApplicationModelConvention继承IApplicationModelConvention,并实现接口:apply绑定控制器、方法模型。
2、其中方法:ConfigureApiExplorer,设置控制器、方法对外可见。通过设置属性:ApiExplorer。在Asp.net core中,API默认对外可见,如果没设置也可以。
3、方法:ConfigureSelector,用于初始化路由、Http请求方法。

2.3 添加动态方法

在Program.cs项目入口,添加动态方法。

Program.cs
//添加动态方法 builder.Services.AddMvc(m => { m.Conventions.Add(new AutoApplicationModelConvention()); });

image

2.4 测试

测试效果如下:
1、控制器名称,路由名称都已去掉后缀:AppService。
2、接口正常请求结果。
3、请求方法为Get。
image


__EOF__

本文作者羊徒
本文链接https://www.cnblogs.com/ayy-200248/p/18444714.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   羊徒  阅读(79)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示