动态WebAPI #
小知识 动态WebAPl实际上就是将普通的类变为Controller,也就是动态WebAPl就是控制器,支持控制器一切功能。
什么是控制器 #
简单来说,控制器是一个承上启下的作用,根据用户输入,执行响应行为(动作方法),同时在行为中调用模型的业务逻辑,返回给用户结果(视图)。
 在ASP.NET core中,控制器有两种表现形式:
• MVC (带视图)
• WebAPl (RESTful API)
• Mvc控制器
在ASP.NET core中,控制器有两种表现形式:
• MVC (带视图)
• WebAPl (RESTful API)
• Mvc控制器
using MiCrosoft.AspNetCore.MVC;
namespaCe XXXX.Web.Entry.Controllers {
    publiC Class MVCController : Controller
    {
        publiC IACtionResult Index()
        {
            return View();
        }
    }
}
• WebAPI控制器
using MiCrosoft.AspNetCore.MVC;
namespaCe XXXX.Web.Entry.Controllers
{
    [Route("api/[Controller]")]
    publiC Class WebApiController : ControllerBase{
    [HttpGet]
    public IActionResult Get()
    {
    	return Content(nameof(Mall3s));
    }
   }
}
MVC控制器和WebAPl控制器最大的区别是WebAPl控制器不带视图和通过请求谓词和路由地址响应行为。
MVC控制器约定和缺点 #
在学习动态WebAPl控制器之前,首先了解ASP.NET core中WebAPl的一些约定和注意事项。
WebAPI 约定 #
 在 ASP.NET Core 应用中,一个 WebAPI 控制器需遵循以下约定:
- 控制器类必须继承 ControllerBase或间接继承
- 动作方法必须贴有 [HttpMethod]特性,如:[HttpGet]
- 控制器或动作方法至少有一个配置 [Route]特性
- 生成 WebAPI路由地址时会自动去掉控制器名称Controller后缀,同时也会去掉动作方法匹配的HttpVerb谓词,如GET,POST,DELETE,PUT等
- 不支持返回非 IEnumerable<T>泛型对象
- 不支持类类型参数在 GET,HEAD请求下生成Query参数
除了上述约定外,WebAPI 路由地址基本靠手工完成,不利于书写,不利于维护,再者,在移动应用对接中难以进行多版本控制。
.NET Core WebAPI 缺点 #
 通过上一章节可以看出,ASP.NET Core 应用实现 WebAPI 需要遵循种种约定,而且容易出错。
除了这些约定,.NET Core WebAPI 有以下缺点:
- 路由地址基本靠手工完成
- 在现在移动为王的时代,不利于进行多版本控制
- 对接 Swagger文档分组比较复杂
- 实现 Policy策略授权也比较复杂
- 不支持控制器热插拔插件化
- 难以实现复杂自定义的 RESTful API风格
动态 WebAPI 控制器 #
 针对以上 ASP.NET Core 提供的 WebAPI 必须遵循的约定和不可避免的缺点,Mall3s 框架创造出一种更加灵活创建 WebAPI 控制器的方式。
这个方式在继承了 ASP.NET Core WebAPI 所有优点,同时进行了大量拓展和优化。优化后的 WebAPI 具有以下优点:
- 具备原有的 ControllerBase所有功能
- 支持任意公开 非静态 非抽象 非泛型类转控制器
- 提供更加灵活方便的 IDynamicApiController空接口或[DynamicApiController]特性替代ControllerBase抽象类
- 可直接在任意公开 非静态 非抽象 非泛型类贴 [Route]特性自动转控制器
- 无需手动配置 [HttpMethod]特性,同时支持一个动作方法多个HttpVerb
- 无需手动配置 [Route]特性,支持更加灵活的配置及自动路由生成
- 支持返回泛型接口,泛型类
- 和 Swagger深度结合,提供极其方便的创建Swagger分组配置
- 支持 Basic Auth,Jwt,ApiKey等多种权限灵活配置
- 支持控制器、动作方法版本控制功能
- 支持 GET、HEAD请求自动转换类类型参数
- 支持生成 OAS3接口规范
注册动态WebAPI 服务 #
小提示
.AddDynamicApiControllers() 默认已经集成在 AddInject() 中了,无需再次注册。也就是下列代码可不配置。
using Microsoft.Extensions.DependencyInjection;
namespace XXXX.Web.Core
{
    [AppStartup(800)]
    public sealed class WebCoreStartup : AppStartup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers()
            .AddDynamicApiControllers();
        }
    }
}
::: 特别注意
.AddDynamicApiControllers() 必须在 services.AddControllers() 之后注册。
:::
第一个例子 #
创建一个 Mall3sAppService 类继承 IDynamicApiController 接口 或 贴 [DynamicApiController] 特性,并在这个类中编写一个 Get 方法。
- IDynamicApiController方式
using Mall3s.DynamicApiController;
namespace XXXX.Application
{
    public class Mall3sAppService : IDynamicApiController {
        public string Get()
        {
            return $"Hello {nameof(Mall3s)}";
        }
    }
}
- [DynamicApiController] 方式
using Mall3s.DynamicApiController;
namespace XXXX.Application
 [DynamicApiController] 
 public class Mall3sAppService {
    public string Get()
    {
    return $"Hello {nameof(Mall3s)}";
    }
 }
如下图所示,一个WebAPI 接口就这么生成了。
动态WebAPi 原理解析 #
控制器特性提供器 #
Mall3s 框架会在应用启动时注册DynamicApiControllerFeatureProvider 控制器特性提供器,该提供器继承自ControllerFeatureProvider 类。 接着重写bool IsController(TypeInfo typeInfo) 方法,用来标识控制器类型。在Mall3s 框架中,继承自ControllerBase 类或IDynamicApiController 接口或[DynamicApiController] 特性都会被标记为控制器类型。
应用模型转换器 #
Mall3s 框架同时在应用启动时注册DynamicApiControllerApplicationModelConvention 应用模型转换器,该转换器继承自IApplicationModelConvention 接口。 接着实现void Apply(ApplicationModel application) 接口方法。在该方法中配置控制器名称、路由、导出可见性及动作方法名称、路由、导出可见性等。 实际上该方法做的就是按照WebAPI 约定提前帮我们配置好路由、请求谓词等信息。避免了手动配置的同时还增加了许多新特性,如版本控制。
动态WebAPI 配置约定 #
控制器默认约定 #
- 生成控制器名称默认去除以 AppServices,AppService,ApiController,Controller,Services,Service作为前后缀的字符串。见第一个例子中的Mall3sAppService -> Mall3s支持自定义配置
- 控制器名称带 V[0-9_]结尾的,会自动生成控制器版本号,如Mall3sAppServiceV2 -> Mall3s@2,Mall3sAppServiceV1_1_0 -> Mall3s@1.1.0。支持版本分隔符配置
- 控制名称以 骆驼命名(CamelCase)会自动切割成多个单词-连接。支持自定义配置
动作方法默认约定 #
- 生成的动作方法名称默认去除以 Post/Add/Create/Insert/Submit,GetAll/GetList/Get/Find/Fetch/Query/Search,Put/Update,Delete/Remove/Clear,Patch开头的字符串。支持自定义配置
- 生成的动作方法名称默认去除以 Async作为前后缀的字符串。支持自定义配置
- 动作方法名称带 V[0-9_]结尾的,会自动生成动作方法版本号,如ChangePasswordV2 -> ChangePassword@2,ChangePasswordV1_1_0 -> ChangePassword@1.1.0。支持版本分隔符配置
- 动作方法名称以 骆驼(驼峰)/帕斯卡命名(CamelCase/Pascal)会自动切割成多个单词-连接。支持自定义配置
- 动作方法参数将自动转为小写。支持自定义配置
请求谓词默认约定 #
- 动作方法名
- 以 Post/Add/Create/Insert/Submit/Change开头,则添加[HttpPost]特性。
- 以 GetAll/GetList/Get/Find/Fetch/Query开头,则添加[HttpGet]特性。
- 以 Put/Update开头,则添加[HttpPut]特性。
- 以 Delete/Remove/Clear开头,则添加[HttpDelete]特性。
- 以 Patch开头,则添加[HttpPatch]特性
- 支持自定义配置
 
- 以 
- 如果不在上面约定中,则默认添加 [HttpPost]特性。支持自定义配置
路由地址默认约定 #
- 默认以 api开头。支持自定义配置
- 默认转换为小写路由地址。支持自定义配置
- 生成控制器路由模板格式为:api/前置参数列表/模块名或默认区域名/[controller@版本号]/后置参数列表
- 生成动作方法路由模板格式为:前置参数列表/模块名/[action@版本号]/后置参数列表
其他约定 #
- 默认不处理 ControllerBase控制器类型。支持自定义配置
- 默认不处理 GET,HEAD请求的引用类型参数。支持自定义配置
更多例子 #
多种请求谓词方法 #
using Mall3s.DynamicApiController;
namespace Mall3s.Application
{
    public class Mall3sAppService : IDynamicApiController
    {
        public string Get()
        {
     	   return $"GET 请求";
        }
        public string Post()
        {
      	  return $"POST 请求";
        }
        public string Delete()
        {
     	   return $"DELETE 请求";
        }
        public string Put()
        {
     	   return $"PUT 请求";
        }
        public string Patch()
        {
      	  return $"PATCH 请求";
        }
    }
}
如下图所示:

多个自定义动作方法 #
using Mall3s.DynamicApicontroller;
namespace Mall3s.Application
{
    public class Mall3sAppService : IDynamicApicontroller
    {
        public string GetVersion()
        {
       		 return $"v1.0.0";
        }
        public string changeProfile()
        { 
        	return " 修改成功";
        }
        public string DeleteUser()
        { 
        	return " 删除成功";
        }
   }
}
带参数动作方法 #
using Mall3s.DynamicApiController;
namespace Mall3s.Application
{
    public class Mall3sAppService : IDynamicApiController {
    public string GetUser(int id)
    {
   		 return $"{id}";
    }
    public string GetUser(int id, string name)
    {
    	return $"{id} {name}";
    }
    public TestDto Add(TestDto testDto)
    {
   		 return testDto;
    }
}
GET/HEAD 类类型参数 #
默认情况下,ASP.NET Core 会将GET/HEAD 请求中的类类型参数设置为[FromBody] 绑定,如
using Mall3s.DynamiCApiController;
namespaCe Mall3s.AppliCation
{
    publiC Class Mall3sAppSerViCe : IDynamiCApiController
    {
        publiC TestDto GetTest(TestDto testDto)
        {
        	return testDto;
        }
    }
}
如下图所示:

但是,GET、HEAD 请求不支持 From Body 绑定。所以我们需要转换为 Query 查询参数。
Mall3s 框架支持以下两种方式配置:
- [FromQuery] 特性
using Mall3s.DynamicApicontroller;
using Microsoft.AspNetcore.Mvc;
namespace Mall3s.Application
{
    public class Mall3sAppService : IDynamicApicontroller
    {
        public TestDto GetTest([FromQuery] TestDto testDto)
        {
       	 return testDto;
        }
    }
}
- 配置DynamicApiControllerSettings
Mall3s.Web.Entry/appsettings.json
{
    "DynamicApicontrollerSettings": 
    { 
    	"ModelToQuery": true
    }
}
自定义参数位置 #
Mall3s 框架提供了非常方便的自定义参数位置的特性[ApiSeat] ,通过[ApiSeat] 可配置参数位置,支持以下四种位置:
- ApiSeats.ControllerStart:控制器之前
- ApiSeats.ControllerEnd:控制器之后
- ApiSeats.ActionStart:动作方法之前
- ApiSeats.ActionEnd:动作方法之后。默认值
温馨提示 多个同位置配置的参数将按照定义参数顺序进行排序。 特别注意 [ApiSeat] 只能应用于贴了[FromRoute] 特性的参数或基元类型、值类型、可空基元类型和可空值类型。
自定义请求谓词 #
using Mall3s.DynamicApiController;
using Microsoft.AspNetCore.Mvc;
namespace Mall3s.Application
{
    public class Mall3sAppService : IDynamicApiController
    {
        [HttpPost]
        public string GetVersion()
        {
        	return "1.0.0";
        }
    }
}
支持多个谓词 #
using Mall3s.DynamicApiController;
using Microsoft.AspNetCore.Mvc;
namespace Mall3s.Application
{
 public class Mall3sAppService : IDynamicApiController {
	[HttpPost, HttpGet, AcceptVerbs("PUT", "DELETE")] 
	public string GetVersion()
    {
    return "1.0.0";
    }
 }
}
特别注意 如果动作方法中含有类类型参数,且含有POST/PUT/DELETE 任意请求谓词,那么该参数会自动添加[FromBody] 参数,即使在GET/HEAD 请求中不支持。
支持自定义路由 #
支持控制器和动作方法自定义路由: 自定义控制器路由
using Mall3s.DynamicApicontroller;
using Microsoft.AspNetcore.Mvc;
namespace Mall3s.Application
{
    [Route("customapi/mobile/[controller]")]
    public class Mall3sAppService : IDynamicApicontroller
    {
        public string GetVersion()
        {
       	 return "1.0.0";
        }
    }
}
自定义动作方法路由
using Mall3s.DynamicApicontroller;
using Microsoft.AspNetcore.Mvc;
namespace Mall3s.Application
{
    public class Mall3sAppService : IDynamicApicontroller {
       [Route("customapi/[action]")]
        public string GetVersion()
        {
      	  return "1.0.0";
        }
    }
}
同时自定义路由
using Mall3s.DynamicApiController;
using Microsoft.AspNetCore.Mvc;
namespace Mall3s.Application
{
    [Route("customapi/mobile/[controller]")] 
    public class Mall3sAppService : IDynamicApiController {
        [Route("get/[action]")] public string GetVersion()
        {
       		 return "1.0.0";
        }
    }
}
谓词自定义路由
using Mall3s.DynamicApiController;
using Microsoft.AspNetCore.Mvc;
namespace Mall3s.Application
{
    [Route("api/[controller]")]
    public class Mall3sAppService : IDynamicApiController {
        [HttpGet("get/[action]")] 
        public string GetVersion()
        {
        	return "1.0.0";
        }
    }
}
如下图所示:
 :::tip 小提示
:::tip 小提示
动作方法自定义路由如果以 / 开头,则不会合并控制器路由。
:::
推荐配置
自定义路由如果需要用到 控制器/动作方法名称,推荐使用 [controller] 或 [action] 占位符,因为该占位符已经自动处理了 前后缀、版本号、模块名称等。
多路由随意组合 #
Mall3s 框架提供了非常灵活的各种路由组合方式,支持一对多,多对多路由组合:
using Mall3s.DynamicApiController;
using Microsoft.AspNetCore.Mvc;
namespace Mall3s.Application
{
    [Route("api/[controller]")] 
    [Route("api/[controller]/second")] 
    [Route("api/[controller]/three")] 
    public class Mall3sAppService : IDynamicApiController {
        [HttpGet]
        [HttpGet("get/[action]")]
        [HttpPost] [HttpPost("post/cus-version")] 
        public string GetVersion()
        {
        	return "1.0.0";
        }
}
如下图所示:

特别注意 动作方法不能同时贴[Route] 和[HttpMethod] 特性,只能二取一
支持版本控制 #
控制器版本
using Mall3s.DynamicApicontroller;
namespace Mall3s.Application
{
        public class Mall3sAppServiceV1 : IDynamicApicontroller
        {
            public string Get()
            {
                return nameof(Mall3s);
            }
        }
        public class Mall3sAppServiceV1_2 : IDynamicApicontroller
        {
            public string Get()
            {
                return nameof(Mall3s);
            }
        }
        public class Mall3sAppServiceV1_2_1 : IDynamicApicontroller
        {
            public string Get()
            {
                return nameof(Mall3s);
            }
   	    }
}
动作方法版本
using Mall3s.DynamicApiController;
namespace Mall3s.Application
{
    public class Mall3sAppService : IDynamicApiController {
        public string Get()
        {
        	return nameof(Mall3s);
        }
        public string GetV1()
        {
        	return nameof(Mall3s);
        }
        public string GetV2_1()
        {
        	return nameof(Mall3s);
        }
    }
}
如下图所示:

版本生成原理 V[0-9_] 结尾的命名自动解析成版本号,如Mall3sAppServiceV2 -> Mall3s@2 。 版本复写 除了通过特定后缀方式以外,版本还直接通过[ApiDescriptionSettings] 进行复写。如
[ApiDescriptionSettings(Version = "4.0")]
public string GetV1()
{
	return nameof(Mall3s);
}
这时,生成版本将采用4.0 替代1
不公开控制器或动作方法 #
有些时候,我们无需导出某个动作方法或控制器(不显示到 Swagger),只需要添加 [ApiDescriptionSettings(false)] 或 [ApiExplorerSettings(IgnoreApi = true)]即可。
另外动作方法还支持 [NonAction] 标记不是一个有效的控制器或 Action。
推荐使用
推荐控制器或动作方法设置不导出使用 [ApiDescriptionSettings(false)] 特性。该特性默认继承自 ApiExplorerSettingsAttribute 类。
保持控制器和方法命名 #
默认情况下,动态API 会将控制器和方法名输出为RESTFul 风格的路由,如需保留原有设计,只需配置:
{
"DynamicApiControllerSettings": {
"KeepName": true,
"KeepVerb": true,
"LowercaseRoute": false
}
}
方法参数[FromQuery] 化/参数非必填/参数可选 #
默认情况下,所有的基元类型参数都会贴上 [FromRoute] 特性,如果需要将参数调整为 [FromQuery] 修饰,只需要在方法上面贴 [QueryParameters] 特性即可,如:
[QueryParameters]
public string Get(int id, string name)
{
	return nameof($"{id} {name}");
}
生成的路由为:https://xxx.com?id=1&name=Mall3s 如果不喜欢每个都配置,也可以全局配置(只会影响基元类型的参数):
{
"DynamicApiControllerSettings": {
"UrlParameterization": true
}
}
特别注意
贴了 [QueryParameters] 之后,会对所有参数影响,包括类类型参数,如果不需要处理某个参数,只需要贴 [FromXXX] 特性即可。
参数绑定配置 #
Mall3s 框架提供了多种参数特性配置参数绑定规则:
- [FromRoute]:通过路由参数绑定值
- [FromQuery]:通过- Url地址参数绑定值
- [FromBody]:通过- Request Body参数绑定值
- [FromForm]:通过表单提交绑定值
- [FromHeader]:通过- Request Header参数绑定值
自定义根据方法名生成[HttpMethod] 规则 #
在Mall3s 框架中,在没有配置 [HttpMethod] 特性的情况下,会自动根据方法名第一个参数进行分析,并生成对应的 [HttpMethod] 特性,规则如下:
- 动作方法名
- 以 Post/Add/Create/Insert/Submit开头,则添加[HttpPost]特性。
- 以 GetAll/GetList/Get/Find/Fetch/Query开头,则添加[HttpGet]特性。
- 以 Put/Update开头,则添加[HttpPut]特性。
- 以 Delete/Remove/Clear开头,则添加[HttpDelete]特性。
- 以 Patch开头,则添加[HttpPatch]特性
- 以 Head开头,则添加[HttpHead]特性
- 支持自定义配置
 
- 以 
- 如果不在上面约定中,则默认添加 [HttpPost]特性。支持自定义配置
但是,有些时候这不是我们想要的规则,这时我们只需要在 appsettings.json 中配置即可:
{
    "DynamicApiControllerSettings": { "VerbToHttpMethods": [
    ["getall”,"HEAD”], // => getall 会被复写为' [HttpHead]'
    ["other", "PUT"] // =>新增一条新规则,比如,一'[other]'开头会转换为'[HttpPut]' 请求
    ]
    }
}
特别注意
二维数组中的每一个元素的第一个元素必须是全小写,第二个元素必须是全大写大写,第二个元素取值有:HEAD, GET, PUT, POST, PATCH, DELETE
路由参数非必填/选填 #
在Mall3s 最新版本中实现了[FromRoute] 参数非必填功能,支持以下几种方式:
// 方式一,通过可空?
public object Method1(int id, Datetime? dateTime)
{
}
// 方式二,通过默认值
public object Method1(int id, int age = 10)
{
}
// 方式三,默认值+ 可空?
public object Method1(int id, int? age = 10)
{
}
//方式四,[FromQuery]修饰
public object Method1(int id, [FromQuery]string keyword)
{
}
[FormRoute] 路由约束 #
在Mall3s 最新版本中,添加了[RouteConstraint] 特性,可配置路由约束,如
[RouteConstraint(":min(10)")]
// 最小值10
public object Method1([RouteConstraint(":min(10)")] int id)
{
}
[RouteConstraint] 支持路由约束符号如下:
| 符号 | 描述 | 例子 | 
|---|---|---|
| alpha | 匹配大写或小写拉丁字母字符(a-z、A-Z) | :alpha | 
| bool | bool 类型 | :bool | 
| datetime | DateTime 类型 | :datetime | 
| decimal | decimal 类型 | :decimal | 
| double | double 类型 | :double | 
| float | float 类型 | :float | 
| guid | guid 类型 | :guid | 
| int | int 类型 | :int | 
| long | long 类型 | :long | 
| length | 匹配长度(字符串) | :length(6) 或 :length(1,20) | 
| max | 最大值 | :max(10) | 
| maxlength | 最大长度(字符串) | :maxlength(10) | 
| min | 最小值 | :min(10) | 
| minlength | 最小长度(字符串) | :minlength(10) | 
| range | 取值范围 | :range(10,50) | 
| regex | 正则表达式 | :regex(心d{3}-\d{3}-\d{4}$) | 
[ApiDescriptionSettings] #
除了上述ASP.NET Core 提供的配置外,Mall3s 框架还提供了非常强大且灵活的[ApiDescriptionSettings] 特性。
内置配置 #
- Name:自定义控制器/动作方法名称,- string,默认- null
- KeepName:是否保持原有名称不处理,- bool,默认- false
- SplitCamelCase:切割骆驼(驼峰)/帕斯卡命名,- bool,默认- true
- KeepVerb:是否保留动作方法请求谓词,- bool,默认- false
- Enabled:是否导出接口,- bool,默认- true
- Module:模块名,- string,默认- null
- Version:版本号,- string,默认- null
- Groups:接口分组,可结合- Swagger一起使用,- string[],默认- null
- Tags:接口标签,可结合- Swagger一起使用,- string[],默认- null
- Order:配置控制器/动作方法排序
- LowercaseRoute:是否采用小写路由,- bool类型,默认- true
- AsLowerCamelCase:启用小驼峰命名(首字母小写),默认- false
- Area:配置区域名称,默认空,只作用于类中贴
- Description:配置单一接口更多描述功能,只在- 方法中有效,****
- ForceWithRoutePrefix:配置是否强制添加- DefaultRoutePrefix,当控制器自定义了- [Route]有效,默认- false,
Name 配置 #
Name 参数可以覆盖动态WebAPI 自动生成的控制器或动作方法名称。如
using Mall3s.DynamicApiController;
namespace Mall3s.Application
    {
    [ApiDescriptionSettings(Name = "MyMall3s")] 
    public class Mall3sAppService : IDynamicApiController {
    [ApiDescriptionSettings(Name = "MyGet")] 
    public string Get()
    {
    	return nameof(Mall3s);
    }
    }
}
如下图所示:

KeepName 配置 #
KeepName 参数可以保留原有的控制器或动作方法名称。如:
using Mall3s.DynamicApiController;
namespace Mall3s.Application
{
    [ApiDescriptionSettings(KeepName = true)]
    public class Mall3sAppService : IDynamicApiController
    {
        [ApiDescriptionSettings(KeepName = true)]
        public string Get()
        {
            return nameof(Mall3s);
        }
    }
}
如下图所示:

Splitcamelcase 配置 #
Splitcamelcase 参数默认将骆驼(驼峰)命名切割成多个单词并通过指定占位符连接起来。默认占位符为-。默认为true。如:
using Mall3s.DynamicApicontroller;
namespace Mall3s.Application
{
    [ApiDescriptionSettings(Splitcamelcase = false)] 
    public class MyMall3sAppService : IDynamicApicontroller {
    [ApiDescriptionSettings(Splitcamelcase = true)] 
    public string changeUserName()
    {
    	return nameof(Mall3s);
    }
    }
}
如下图所示:

特别注意 KeepName 优先级高于SplitCamelCase ,也就是KeepName 设置为true ,则不会处理SplitCamelCase 参数。
KeepVerb 配置 #
KeepVerb 参数作用于动作方法,标识是否保留动作谓词。如:
using Mall3s.DynamicApiController;
namespace Mall3s.Application
{
    public class Mall3sAppService : IDynamicApiController {
    [ApiDescriptionSettings(KeepVerb = true)] 
    public string GetVersion()
    {
    	return nameof(Mall3s);
    }
}

Enabled 配置 #
Enabled 参数配置接口是否导出。通常用于动作方法,如果用于控制器实际作用不大
using Mall3s.DynamicApiController;
namespace Mall3s.Application
{
  public class Mall3sAppService : IDynamicApiController
  {
    public string GetVersion()
    {
    	return nameof(Mall3s);
    }
    [ApiDescriptionSettings(false)]
    public string NoExport()
    {
    	return nameof(Mall3s);
    }
 }
}

Module 配置 #
Module 参数可以配置路由分离,类似于Mvc 区域的作用。
using Mall3s.DynamicApiController;
namespace Mall3s.Application
{
    [ApiDescriptionSettings(Module = "mobile")] 
    public class Mall3sAppService : IDynamicApiController {
    	[ApiDescriptionSettings(Module = "user")] 
        public string GetVersion()
        {
        	return nameof(Mall3s);
        }
    }
}

Version 配置 #
Version 参数可以配置接口版本,同时又可以复写特殊版本命名配置。默认版本分隔符为@ 。如
using Mall3s.DynamicApiController;
namespace Mall3s.Application
{
    [ApiDescriptionSettings(Version = "1.0")]
    public class Mall3sAppService : IDynamicApiController
    {
    // V2.0.0 被复写成V2.1.1
    [ApiDescriptionSettings(Version = "2.1.1")]
    public string GetVersionV2_0_0()
    {
    return nameof(Mall3s);
    }
}
 #
 #
 Groups 配置 #
Groups 配置主要用于配置Swagger 分组信息。 通过配置Groups 参数可以将控制器和动作方法进行归类和多个分组直接共享。可通过 [ApiDescriptionSettings(params Groups)] 构造函数传入或指定Groups 参数配置接口是否导出。通常用于动作方法,如果用于控制器实际作用不大。
using Mall3s.DynamicApicontroller;
namespace Mall3s.Application
{
    [ApiDescriptionSettings("Default", "common")] 
    public class Mall3sAppService : IDynamicApicontroller {
    public string Get()
    {
    	return nameof(Mall3s);
    }
    [ApiDescriptionSettings("custom")] 
    public int Get(int id)
    {
    	return id;
    }
    }
}
如下图所示:

Tag 配置 #
Tag 配置主要用于配置Swagger 标签分组信息及合并标签。也就是组中组: 标签命名 未贴标签之前
using Mall3s.DynamicApiController;
namespace Mall3s.Application
{
    public class Mall3sAppService : IDynamicApiController {
        public string Get()
        {
        	return nameof(Mall3s);
        }
        public int Get(int id)
        {
        	return id;
        }
    }
    public class TestAppService : IDynamicApiController {
        public string Get()
        {
        	return nameof(Mall3s);
        }
        public int Get(int id)
        {
        }
    }
}
贴标签之后
using Mall3s.DynamicApiController;
namespace Mall3s.Application
{
    [ApiDescriptionSettings(Tag = "分组一")] 
    public class Mall3sAppService : IDynamicApiController {
        public string Get()
        {
            return nameof(Mall3s);
        }
        public int Get(int id)
        {
            return id;
        }
    }
    [ApiDescriptionSettings(Tag = "分组二")] 
    public class TestAppService : IDynamicApiController {
        public string Get()
        {
        	return nameof(Mall3s);
        }
        public int Get(int id)
        {
        	return id;
        }
    }
}
合并标签
using Mall3s.DynamicApiController;
namespace Mall3s.Application
{
    [ApiDescriptionSettings(Tag = "合并所有标签")] 
    public class Mall3sAppService : IDynamicApiController {
    public string Get()
    {
    	return nameof(Mall3s);
    }
    public int Get(int id)
    {
    }
 }
    [ApiDescriptionSettings(Tag = "合并所有标签")] 
    public class TestAppService : IDynamicApiController {
        public string Get()
        {
            return nameof(Mall3s);
        }
        public int Get(int id)
        {
            return id;
        }
    }
}
如下图所示:

小知识 如果Tag 名字一样,则会自动合并,否则只是命名
DynamicApiControllerSettings 配置 #
mall3s 还提供动态 WebAPI 接口一些全局配置选项,如:
- DefaultRoutePrefix:默认路由前缀,- string,默认- api
- DefaultHttpMethod:默认请求谓词,- string,默认:- POST
- DefaultModule:默认模块名称(区域),可用作接口版本,- string,默认:- v1
- LowercaseRoute:小写路由格式,- bool,默认:- true
- AsLowerCamelCase:启用小驼峰命名(首字母小写),默认- false
- KeepVerb:是否保留动作谓词,- bool,默认:- false
- KeepName:是否保留默认名称,- bool,默认:- fasle
- CamelCaseSeparator:骆驼(驼峰)/帕斯卡命名分隔符,- string,默认:- -
- VersionSeparator:版本分隔符,- string,默认:- @
- ModelToQuery:- GET/HEAD请求将- 类类型参数转查询参数,- bool,默认- false
- SupportedMvcController:是否支持- Mvc Controller动态配置,- bool,默认- false
- UrlParameterization:路由参数采用- [FromQuery]化,默认- false(- [FromRoute]方式)
- DefaultArea:配置默认区域,默认- null
- ForceWithRoutePrefix:配置是否强制添加- DefaultRoutePrefix,当控制器自定义了- [Route]有效,仅限 v3.4.1+版本有效
- AbandonControllerAffixes:默认去除控制器名称前后缀列表名,- string[],默认:- AppServices
- AppService
- ApiController
- Controller
- Services
- Service
 
- AbandonActionAffixes:默认去除动作方法名称前后缀列表名,- string[],默认:- Async
 
- VerbToHttpMethods:复写默认方法名转- [HttpMethod]规则,- string[][]二维数组类型,内置匹配规则为:
["post"] = "POST",
["add"] = "POST",
["create"] = "POST",
["insert"] = "POST",
["submit"] = "POST",
["get"] = "GET",
["find"] = "GET",
["fetch"] = "GET",
["query"] = "GET",
["put"] = "PUT",
["update"] = "PUT",
["delete"] = "DELETE",
["remove"] = "DELETE",
["clear"] = "DELETE",
["patch"] = "PATCH"
复写示例
"DynamicApiControllerSettings": {
    "VerbToHttpMethods": [
      [ "getall", "HEAD" ],  // => getall 会被复写为 `[HttpHead]`
      [ "other", "PUT" ]  // => 新增一条新规则,比如,一 `[other]` 开头会转换为 `[HttpPut]` 请求
    ]
  }
支持Mvc 控制器动态配置 #
默认情况下,Mall3s 动态WebAPI 接口不对ControllerBase 类型进行任何处理。当然,我们也可以手动启用ControllerBase 支持。 XXXX.Web.Entry/appsettings.json
{
"DynamicApiControllerSettings": { "SupportedMvcController": true
}
}
设置SupportedMvcController: true 后,Mvc ControllerBase 类型也能和动态WebAPI 一样的灵活了。代码如下:
using Microsoft.AspNetCore.Mvc;
namespace Mall3s.Web.Entry.Controllers
{
    public class MvcController : ControllerBase
    {
        public string Get()
        {
            return nameof(Mall3s);
        }
    }
}
注意事项 启用该配置后,如果Mvc 控制器没有任何[Route] 特性,但是贴了[ApiController] 特性将会报错。原因是[ApiController] 特性内部做了路由特性检测。所以建议使用[ApiDataValidation] 代替。 查看ASP.NET Core-ApiBehaviorApplicationModelProvider源码 (opens new window)
关于AOP 拦截 #
动态webAPl支持Controller的所有过滤器/筛选器拦截,也就是可以通过ActionFilter , ResultFilter 进行拦截操作。如:
public class SampleAsyncActionFilter : IAsyncActionFilter
{
    public async Task OnActionExecutionAsync(ActionExecutingContext context,ActionExecutionDelegate next)
    {
        // 拦截之前
        var resultContext = await next();
        // 拦截之后
        // 异常拦截
        if(resultContext.Exception != null)
        }
    }
}
详细用法可参见ASP.NET Core5.0 -筛选器 (opens new window)
设置api 超时请求时间 #
在Program.cs 中添加.UseKestrel 配置即可,如:
public static IHostBuilder CreateHostBuilder(string[] args)
{
    return Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder =>
    {
    webBuilder.Inject()
    .UseStartup<Startup>()
    .UseKestrel(option =>
    {
        option.Limits.KeepAliveTimeout =
        TimeSpan.FromMinutes(20);
        option.Limits.RequestHeadersTimeout =
        TimeSpan.FromMinutes(20);
        });
    });
}
