首页 > 其他分享 >【动态Web API学习(三)】动态方法

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

时间:2024-10-02 14:33:30浏览次数:9  
标签:Web 控制器 selector var controller API action new 动态

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

标签:Web,控制器,selector,var,controller,API,action,new,动态
From: https://www.cnblogs.com/ayy-200248/p/18444714

相关文章

  • 静态合批和动态合批
    动态合批与静态合批其本质是对将多次绘制请求,在允许的条件下进行合并处理,减少cpu对gpu绘制请求的次数,达到提高性能的目的。两者是否开启都可以在ProjectSettings->Player->OtherSettings下的StaticBatching和DynamicBatching1.静态合批是将静态(不移动)GameObjects组......
  • pbootcms增加webp和mov等上传文件类型的方法
    在PBootCMS中,如果需要增加一些非常见的文件格式上传,可以通过修改配置文件来实现这一需求。以下是详细的步骤说明:操作步骤1.修改 config.php 文件打开 config.php 文件:文件位置:/config/config.php修改 upload 配置信息:在大约第30行附近找到 upload 配置......
  • 成功地在 PBootCMS 中增加 .webp 和 .mov 文件类型的上传支持
    config.php 文件修改示例<?phpreturnarray(//其他配置...//上传配置'upload'=>array('format'=>'jpg,jpeg,png,gif,xls,xlsx,doc,docx,ppt,pptx,rar,zip,pdf,txt,mp4,avi,flv,rmvb,mp3,otf,ttf,webp,mov',......
  • 动态规划
    动态规划这一篇完全写不完,只能把今天回顾的内容记录一遍,所以之后肯定会补充。概念性知识(使用条件)最优子结构即:一个情形面前只有有限个抉择,那么要想让当前得到的结果最优,那么一定会去贪心地做出选择。无后效性把问题划分成阶段,那么按照逻辑顺序,当前阶段的决策不会受到之后所......
  • 33_分布式文档系统_bulk api的奇特json格式与底层性能优化关系大揭秘
    课程大纲bulkapi奇特的json格式{"action":{"meta"}}\n{"data"}\n{"action":{"meta"}}\n{"data"}\n[{"action":{},"data":{}}]1、bulk中的每个操作都可能要转发到不同的node的shard去执行2、如果采用比较良好的......
  • 26_上机动手实战演练mget批量查询api
    1、批量查询的好处就是一条一条的查询,比如说要查询100条数据,那么就要发送100次网络请求,这个开销还是很大的如果进行批量查询的话,查询100条数据,就只要发送1次网络请求,网络请求的性能开销缩减100倍2、mget的语法(1)一条一条的查询GET/test_index/test_type/1GET/test_index/te......
  • 反射 动态代理
    出自https://www.bilibili.com/video/BV1ke4y1w7yn1.反射1.1反射的概述:​ 专业的解释(了解一下):​是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;​对于任意一个对象,都能够调用它的任意属性和方法;​这种动态获取信息以及动态调用对......
  • 每日OJ题_牛客_DP2跳台阶_动态规划_C++_Java
    目录牛客_DP2跳台阶_动态规划题目解析C++代码Java代码牛客_DP2跳台阶_动态规划跳台阶_牛客题霸_牛客网题目解析        当前值只和数组的前两个值有关,在往前面的就无关了,所以没必要申请一个数组,直接使用两个变量即可,这样空间复杂度就满足要求了。C++代码......
  • [rCore学习笔记 028] Rust 中的动态内存分配
    引言想起我们之前在学习C的时候,总是提到malloc,总是提起,使用malloc现场申请的内存是属于堆,而直接定义的变量内存属于栈.还记得当初学习STM32的时候CubeIDE要设置stack和heap的大小.但是我们要记得,这么好用的功能,实际上是操作系统在负重前行.那么为了实现动态内存分配功......
  • leetcode刷题day34|动态规划Part03 背包问题(01背包问题 二维、01背包问题 一维、416.
    0-1背包问题二维动规五部曲1、确定dp数组以及下标的含义dp[i][j]表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。(取物品时可以是取0-i的任意一个,或者是他们的组合)2、确定递推公式不放物品i:背包容量为j,里面不放物品i的最大价值是dp[i-1][j]......