简介 ZhonTai.DynamicApi 是一款动态 Web API 生成组件,可将符合约定的应用类直接转换为 RESTful 风格的 API。该组件由 ASP.NET Core MVC 原生调用,全程无 Controller 代码与性能损耗。
组件完美集成 Swagger,能够自动生成与手写 Controller 无任何差异的 API 文档。
应用场景 在 DDD 架构的应用逻辑层中,使用本组件可让应用服务直接暴露为 Web API,彻底省去手动编写 Controller 的重复工作。
配置动态 API 在 MyApp.Host 项目下的 Program.cs 文件中配置动态 API:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 new HostApp(new HostAppOptions{ ConfigureDynamicApi = options => { options.NamingConvention = NamingConventionEnum.CamelCase; options.DefaultApiPrefix = "api" ; options.RemoveActionPostfixes.Clear(); options.GetRestFulActionName = (actionName) => actionName; options.AddAssemblyOptions(GetType().Assembly, httpVerb: "POST" ); options.AddAssemblyOptions(GetType().Assembly, apiPreFix: "api" ); options.AddAssemblyOptions(GetType().Assembly, apiPreFix: "api" , httpVerb: "POST" ); AppConsts.HttpVerbs = new Dictionary<string , string >() { ["add" ] = "POST" , ["create" ] = "POST" , ["insert" ] = "POST" , ["submit" ] = "POST" , ["post" ] = "POST" , ["get" ] = "GET" , ["find" ] = "GET" , ["fetch" ] = "GET" , ["query" ] = "GET" , ["update" ] = "PUT" , ["change" ] = "PUT" , ["put" ] = "PUT" , ["batch" ] = "PUT" , ["delete" ] = "DELETE" , ["soft" ] = "DELETE" , ["remove" ] = "DELETE" , ["clear" ] = "DELETE" , }; } }).Run(args );
[!NOTE] 根据前缀动词未匹配到请求方式时,默认使用 HttpPost 方式请求。
NamingConvention 接口命名可选值
命名方式
示例
CamelCase
camelCase
PascalCase
PascalCase
SnakeCase
snake_case
KebabCase
kebab-case
ExtensionCase
extension.case
Custom
自定义,通过options.GetRestFulActionName 设置
使用动态 API 在服务上增加 [DynamicApi(Area = ApiConsts.AreaName)] 特性,并继承 IDynamicApi 接口即可自动生成动态 API:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 [DynamicApi(Area = ApiConsts.AreaName) ] public class ModuleService : BaseService , IModuleService , IDynamicApi { [HttpPost ] public async Task<PageOutput<ModuleListOutput>> GetPageAsync(PageInput<ModuleGetPageDto> input) { var key = input.Filter?.Name; var list = await _moduleRepository.Select .WhereIf(key.NotNull(), a => a.Name.Contains(key)) .Count(out var total) .OrderByDescending(true , c => c.Id) .Page(input.CurrentPage, input.PageSize) .ToListAsync<ModuleListOutput>(); var data = new PageOutput<ModuleListOutput>() { List = list, Total = total }; return data; } }
[!TIP]ApiConsts.AreaName 定义 /api/app/module/get 路径中的 app。
动态 API 根据前缀动词自动生成请求方式,使用 [HttpPost] 特性可覆盖默认请求方式。
新接口文档地址:http://localhost:8010/admin/index.html
Swagger 接口文档地址:http://localhost:8010/admin/swagger/index.html
如果服务是动态 API,开启事务的方法务必定义为 virtual 虚方法,才能正常使用事务拦截。
高级功能 禁用动态 API 在服务方法上添加 [NonAction] 特性,可禁用生成动态 API,变为服务公共方法:
1 2 3 4 5 [NonAction ] public async Task BatchSoftDeleteAsync (long [] ids ){ await _moduleRepository.SoftDeleteAsync(ids); }
重命名 在服务方法上添加特性重命名。API 路径需使用绝对路径:
1 2 3 4 5 [HttpPost(template: "/api/[area]/[controller]/[action]" ) ] public async Task BatchSoftDeleteAsync (long [] ids ){ await _moduleRepository.SoftDeleteAsync(ids); }
排序 服务级别排序:
1 2 3 4 5 6 7 8 [Order(1010) ] [DynamicApi(Area = ApiConsts.AreaName) ] public class ModuleService : BaseService , IModuleService , IDynamicApi { }
[!NOTE] 值越小该服务越靠前。
方法级别排序:
1 2 3 4 5 [Order(1010) ] public async Task BatchSoftDeleteAsync (long [] ids ){ await _moduleRepository.SoftDeleteAsync(ids); }
[!NOTE] 值越大该服务方法越靠前。
多分组 服务级别分组:
1 2 3 4 5 6 7 [DynamicApi(Area = ApiConsts.AreaName, GroupNames = new string[ ] { AdminConsts.AreaName })] public class ModuleService : BaseService , IModuleService , IDynamicApi { }
方法级别分组:
1 2 3 4 5 6 7 [ApiGroup(ApiConsts.AreaName, AdminConsts.AreaName) ] public async Task BatchSoftDeleteAsync (long [] ids ){ await _moduleRepository.SoftDeleteAsync(ids); }
[!TIP] 接口不分组:[ApiGroup(NonGroup = true)]
返回当前数据 添加 [NonFormatResult] 特性可禁用统一包装的数据格式,直接返回当前数据:
1 2 3 4 5 6 7 8 9 10 { "success" : true , "code" : null , "msg" : null , "data" : 1 } 1
1 2 3 4 5 6 7 [NonFormatResult ] public async Task<long > AddAsync (ModuleAddInput input ){ var entity = input.Adapt<ModuleEntity>(); await _moduleRepository.InsertAsync(entity); return entity.Id; }
授权(v8.3.0+) 在服务方法上添加 [ApiAccess("权限点编码")] 特性:
1 2 3 4 5 [ApiAccess("admin:dict:export" ) ] public async Task<ActionResult> ExportListAsync (){ }
[!TIP]
[ApiAccess("权限点编码1", "权限点编码2", All = true)]
权限点编码可设置一个或多个
All 默认为 false,表示满足任意一个权限点编码即可访问
设置为 true 时,需要全部满足才可访问
隐藏 Swagger 文档 添加 [ApiExplorerSettings(IgnoreApi = true)] 特性,接口不会在文档中显示:
1 2 3 4 5 [ApiExplorerSettings(IgnoreApi = true) ] public async Task GetInternalDataForPublicAsync (){ }
禁用操作日志 添加 [NoOperationLog] 特性,接口不会被记录操作日志:
1 2 3 4 5 [NoOperationLog ] public async Task GetDataListAsync (){ }
#中台 #中台/特性注解 #中台/搭建项目框架 #中台/.NET模板 #中台/分布式微服务