@elf-express/admin-net-mcp 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/index.js +83 -88
  2. package/knowledge/Furion_Teaching_Manual/04-1-/351/205/215/347/275/256.md +442 -0
  3. package/knowledge/Furion_Teaching_Manual/04-2-/351/201/270/351/240/205.md +363 -0
  4. package/knowledge/Furion_Teaching_Manual/05-1-/345/213/225/346/205/213WebAPI.md +825 -0
  5. package/knowledge/Furion_Teaching_Manual/05-2-HttpContext.md +217 -0
  6. package/knowledge/Furion_Teaching_Manual/05-3-/347/257/251/351/201/270/345/231/250/346/224/224/346/210/252/345/231/250AOP.md +581 -0
  7. package/knowledge/Furion_Teaching_Manual/05-4-/350/253/213/346/261/202/347/250/275/346/240/270/346/227/245/350/252/214.md +129 -0
  8. package/knowledge/Furion_Teaching_Manual/05-5-/344/270/255/344/273/213/350/273/237/351/253/224Middleware.md +328 -0
  9. package/knowledge/Furion_Teaching_Manual/05-6-Vue-React-Angular/344/273/213/351/235/242/344/273/243/347/220/206.md +317 -0
  10. package/knowledge/Furion_Teaching_Manual/06-1/350/246/217/347/257/204/345/214/226/346/216/245/345/217/243.md +1458 -0
  11. package/knowledge/Furion_Teaching_Manual/06-2/347/254/254/344/270/211/346/226/271API_Scalar.md +91 -0
  12. package/knowledge/Furion_Teaching_Manual/07-/345/217/213/345/245/275/344/276/213/345/244/226/350/231/225/347/220/206.md +511 -0
  13. package/knowledge/Furion_Teaching_Manual/08-1-/350/263/207/346/226/231/351/251/227/350/255/211/345/237/272/347/244/216/344/275/277/347/224/250.md +587 -0
  14. package/knowledge/Furion_Teaching_Manual/10-1-SqlSugar/346/225/264/345/220/210.md +336 -0
  15. package/knowledge/Furion_Teaching_Manual/11-SaaS /345/244/232/347/247/237/346/210/266/347/255/206/350/250/230.md" +271 -0
  16. package/knowledge/Furion_Teaching_Manual/12-furion-dependency-injection.md +408 -0
  17. package/knowledge/Furion_Teaching_Manual/13-/347/211/251/344/273/266/350/263/207/346/226/231/346/230/240/345/260/204/357/274/210Mapster/357/274/211.md +162 -0
  18. package/knowledge/Furion_Teaching_Manual/14-/345/210/206/345/270/203/345/274/217/347/274/223/345/255/230.md +311 -0
  19. package/knowledge/Furion_Teaching_Manual/15-/345/256/211/345/205/250/351/211/264/346/235/203.md +832 -0
  20. package/knowledge/Furion_Teaching_Manual/17-/346/252/242/350/246/226/347/257/204/346/234/254/345/274/225/346/223/216.md +327 -0
  21. package/knowledge/Furion_Teaching_Manual/18-/346/227/245/350/252/214/350/250/230/351/214/204.md +639 -0
  22. package/knowledge/Furion_Teaching_Manual/19-1-HTTP/351/201/240/347/253/257/350/253/213/346/261/202/345/237/272/347/244/216/344/275/277/347/224/250.md +621 -0
  23. package/knowledge/Furion_Teaching_Manual/19-2-HTTP/351/201/240/347/253/257/350/253/213/346/261/202/351/200/262/351/232/216/346/214/207/345/215/227.md +928 -0
  24. package/knowledge/Furion_Teaching_Manual/19-3-HTTP/351/201/240/347/253/257/350/253/213/346/261/202/345/270/270/350/246/213/345/225/217/351/241/214.md +362 -0
  25. package/knowledge/Furion_Teaching_Manual/20-/350/263/207/346/226/231/345/212/240/350/247/243/345/257/206.md +286 -0
  26. package/knowledge/Furion_Teaching_Manual/20-/351/231/204/351/214/204-KSort/350/263/207/346/226/231/347/260/275/345/220/215/345/256/214/346/225/264/345/216/237/345/247/213/347/242/274.md +305 -0
  27. package/knowledge/Furion_Teaching_Manual/21-/345/205/250/347/220/203/345/214/226/345/222/214/346/234/254/345/234/260/345/214/226.md +342 -0
  28. package/knowledge/Furion_Teaching_Manual/22-/344/272/213/344/273/266/345/214/257/346/265/201/346/216/222EventBus.md +448 -0
  29. package/knowledge/Furion_Teaching_Manual/23-JSON/345/272/217/345/210/227/345/214/226.md +340 -0
  30. package/knowledge/Furion_Teaching_Manual/24-/345/215/263/346/231/202/351/200/232/350/250/212SignalR.md +247 -0
  31. package/knowledge/Furion_Teaching_Manual/25-/350/274/224/345/212/251/350/247/222/350/211/262/346/234/215/345/213/231WorkerService.md +295 -0
  32. package/knowledge/Furion_Teaching_Manual/26-1-/346/216/222/347/250/213/344/275/234/346/245/255/345/256/232/346/231/202/344/273/273/345/213/231.md +631 -0
  33. package/knowledge/Furion_Teaching_Manual/26-2-Cron/350/241/250/351/201/224/345/274/217.md +203 -0
  34. package/knowledge/Furion_Teaching_Manual/26-3-/344/273/273/345/213/231/344/275/207/345/210/227TaskQueue.md +215 -0
  35. package/knowledge/Furion_Teaching_Manual/27-/345/210/206/346/225/243/345/274/217ID/347/224/237/346/210/220.md +86 -0
  36. package/knowledge/Furion_Teaching_Manual/28-/346/250/241/347/265/204/345/214/226/351/226/213/347/231/274.md +68 -0
  37. package/knowledge/Furion_Teaching_Manual/29-/346/265/201/350/256/212/347/211/251/344/273/266Clay.md +313 -0
  38. package/knowledge/Furion_Teaching_Manual/30-/350/204/253/346/225/217/350/231/225/347/220/206/357/274/210Sensitive Detection).md" +168 -0
  39. package/knowledge/Furion_Teaching_Manual/32-/346/234/203/350/251/261/345/222/214/347/213/200/346/205/213/347/256/241/347/220/206.md +147 -0
  40. package/knowledge/Furion_Teaching_Manual/33-IPC/347/250/213/345/272/217/351/200/232/350/250/212.md +98 -0
  41. package/knowledge/Furion_Teaching_Manual/34-2-Docker/351/203/250/347/275/262.md +313 -0
  42. package/knowledge/Furion_Teaching_Manual/34-3-Nginx/351/203/250/347/275/262.md +157 -0
  43. package/knowledge/Furion_Teaching_Manual/34-8-WindowsService/351/203/250/347/275/262.md +112 -0
  44. package/knowledge/Furion_Teaching_Manual/35-1-Docker/347/222/260/345/242/203/346/214/201/347/272/214/351/203/250/347/275/262Jenkins.md +169 -0
  45. package/knowledge/Furion_Teaching_Manual/36-1-/345/226/256/345/205/203/346/270/254/350/251/246/346/225/264/345/220/210/346/270/254/350/251/246.md +275 -0
  46. package/knowledge/Furion_Teaching_Manual/36-3-/345/237/272/346/272/226/346/270/254/350/251/246Benchmarking.md +80 -0
  47. package/knowledge/attributes.md +153 -0
  48. package/knowledge/config.md +147 -0
  49. package/knowledge/entity.md +115 -0
  50. package/knowledge/event.md +124 -0
  51. package/knowledge/plugin.md +136 -0
  52. package/knowledge/service.md +146 -0
  53. package/knowledge/sqlsugar.md +172 -0
  54. package/knowledge/vue-typescript.md +338 -0
  55. package/package.json +3 -2
@@ -0,0 +1,825 @@
1
+ # 5.1 动态 WebAPI
2
+
3
+ > **小知识**:动态 WebAPI 实际上就是将普通的类变为 Controller,也就是动态 WebAPI 就是控制器,支持控制器一切功能。
4
+
5
+ ---
6
+
7
+ ## 5.1.1 什么是控制器
8
+
9
+ 简单来说,控制器是一个承上启下的作用,根据用户输入,执行响应行为(动作方法),同时在行为中调用模型的业务逻辑,返回给用户结果(视图)。
10
+
11
+ 在 ASP.NET Core 中,控制器有两种表现形式:Mvc(带视图)和 WebAPI(RESTful API)。Mvc 控制器和 WebAPI 控制器最大的区别是 WebAPI 控制器不带视图和通过请求谓词和路由地址响应行为。
12
+
13
+ ---
14
+
15
+ ## 5.1.2 Mvc 控制器约定和缺点
16
+
17
+ ### 5.1.2.1 WebAPI 约定
18
+
19
+ 在 ASP.NET Core 应用中,一个 WebAPI 控制器需遵循以下约定:
20
+
21
+ - 控制器类必须继承 `ControllerBase` 或间接继承
22
+ - 动作方法必须贴有 `[HttpMethod]` 特性,如 `[HttpGet]`
23
+ - 控制器或动作方法至少有一个配置 `[Route]` 特性
24
+ - 生成 WebAPI 路由地址时会自动去掉控制器名称 `Controller` 后缀,同时也会去掉动作方法匹配的 HttpVerb 谓词
25
+ - 不支持返回非 `IEnumerable<T>` 泛型对象
26
+ - 不支持类类型参数在 GET、HEAD 请求下生成 Query 参数
27
+
28
+ ### 5.1.2.2 .NET Core WebAPI 缺点
29
+
30
+ - 路由地址基本靠手工完成
31
+ - 不利于进行多版本控制
32
+ - 对接 Swagger 文档分组比较复杂
33
+ - 实现 Policy 策略授权也比较复杂
34
+ - 不支持控制器热插拔插件化
35
+ - 难以实现复杂自定义的 RESTful API 风格
36
+
37
+ ---
38
+
39
+ ## 5.1.3 动态 WebAPI 控制器
40
+
41
+ Furion 框架推出一种更加灵活创建 WebAPI 控制器的方式,在继承了 ASP.NET Core WebAPI 所有优点的同时进行了大量扩展和优化:
42
+
43
+ - 具备原有的 `ControllerBase` 所有功能
44
+ - 支持任意公开、非静态、非抽象、非泛型类转控制器
45
+ - 提供 `IDynamicApiController` 空接口或 `[DynamicApiController]` 特性替代 `ControllerBase`
46
+ - 可直接在任意公开非静态非抽象非泛型类贴 `[Route]` 特性自动转控制器
47
+ - 无需手动配置 `[HttpMethod]` 特性,支持一个动作方法多个 HttpVerb
48
+ - 无需手动配置 `[Route]` 特性,支持自动路由生成
49
+ - 支持返回泛型接口、泛型类
50
+ - 和 Swagger 深度结合
51
+ - 支持 Basic Auth、Jwt、ApiKey 等多种权限配置
52
+ - 支持控制器、动作方法版本控制功能
53
+ - 支持 GET、HEAD 请求自动转换类类型参数
54
+ - 支持生成 OAS3 接口规范
55
+
56
+ ---
57
+
58
+ ## 5.1.4 注册动态 WebAPI 服务
59
+
60
+ > **小提示**:`.AddDynamicApiControllers()` 默认已经集成在 `AddInject()` 中了,无需再次注册。
61
+
62
+ ```csharp
63
+ // Furion.Web.Core\FurWebCoreStartup.cs
64
+ using Microsoft.Extensions.DependencyInjection;
65
+
66
+ namespace Furion.Web.Core
67
+ {
68
+ [AppStartup(800)]
69
+ public sealed class FurWebCoreStartup : AppStartup
70
+ {
71
+ public void ConfigureServices(IServiceCollection services)
72
+ {
73
+ services.AddControllers()
74
+ .AddDynamicApiControllers();
75
+ }
76
+ }
77
+ }
78
+ ```
79
+
80
+ > ⚠️ `.AddDynamicApiControllers()` 必须在 `services.AddControllers()` 之后注册。
81
+
82
+ ---
83
+
84
+ ## 5.1.5 第一个例子
85
+
86
+ 创建一个类继承 `IDynamicApiController` 接口或贴 `[DynamicApiController]` 特性:
87
+
88
+ **IDynamicApiController 方式:**
89
+
90
+ ```csharp
91
+ using Furion.DynamicApiController;
92
+
93
+ namespace Furion.Application
94
+ {
95
+ public class FurionAppService : IDynamicApiController
96
+ {
97
+ public string Get()
98
+ {
99
+ return $"Hello {nameof(Furion)}";
100
+ }
101
+ }
102
+ }
103
+ ```
104
+
105
+ **[DynamicApiController] 方式:**
106
+
107
+ ```csharp
108
+ using Furion.DynamicApiController;
109
+
110
+ namespace Furion.Application
111
+ {
112
+ [DynamicApiController]
113
+ public class FurionAppService
114
+ {
115
+ public string Get()
116
+ {
117
+ return $"Hello {nameof(Furion)}";
118
+ }
119
+ }
120
+ }
121
+ ```
122
+
123
+ **[Route("路由模板")] 方式(Furion 4.9.2.19+):**
124
+
125
+ ```csharp
126
+ [Route("[controller]")]
127
+ public class RouteController
128
+ {
129
+ public void Get()
130
+ {
131
+ }
132
+ }
133
+ ```
134
+
135
+ ---
136
+
137
+ ## 5.1.6 动态 WebAPI 原理解析
138
+
139
+ ### 5.1.6.1 控制器特性提供器
140
+
141
+ Furion 框架在应用启动时注册 `DynamicApiControllerFeatureProvider` 控制器特性提供器,重写 `IsController` 方法来标识控制器类型。继承自 `ControllerBase` 类、`IDynamicApiController` 接口或贴 `[DynamicApiController]` 特性都会被标记为控制器类型。
142
+
143
+ ### 5.1.6.2 应用模型转换器
144
+
145
+ 同时注册 `DynamicApiControllerApplicationModelConvention` 应用模型转换器,在其中配置控制器名称、路由、导出可见性及动作方法名称、路由等,按照 WebAPI 约定提前帮我们配置好路由、请求谓词等信息。
146
+
147
+ ---
148
+
149
+ ## 5.1.7 动态 WebAPI 配置约定
150
+
151
+ ### 5.1.7.1 控制器默认约定
152
+
153
+ - 生成控制器名称默认去除以 `AppServices`、`AppService`、`ApiController`、`Controller`、`Services`、`Service` 作为前后缀的字符串(如 `FurionAppService` → `Furion`)。支持自定义配置。
154
+ - 控制器名称带 `V[0-9_]` 结尾的,会自动生成控制器版本号(如 `FurionAppServiceV2` → `Furion@2`,`FurionAppServiceV1_1_0` → `Furion@1.1.0`)。支持版本分隔符配置。
155
+ - 控制名称以骆驼命名(CamelCase)会自动切割成多个单词 `-` 连接。支持自定义配置。
156
+
157
+ ### 5.1.7.2 动作方法默认约定
158
+
159
+ - 生成的动作方法名称默认去除以 `Post/Add/Create/Insert/Submit`、`GetAll/GetList/Get/Find/Fetch/Query/Search`、`Put/Update`、`Delete/Remove/Clear`、`Patch` 开头的字符串。支持自定义配置。
160
+ - 生成的动作方法名称默认去除以 `Async` 作为前后缀的字符串。
161
+ - 动作方法名称带 `V[0-9_]` 结尾的,会自动生成版本号。
162
+ - 动作方法名称以骆驼/帕斯卡命名会自动切割成 `-` 连接。
163
+ - 动作方法参数将自动转为小写。
164
+
165
+ ### 5.1.7.3 请求谓词默认约定
166
+
167
+ | 方法名开头 | 生成特性 |
168
+ |------------|----------|
169
+ | `Post/Add/Create/Insert/Submit/Change` | `[HttpPost]` |
170
+ | `GetAll/GetList/Get/Find/Fetch/Query` | `[HttpGet]` |
171
+ | `Put/Update` | `[HttpPut]` |
172
+ | `Delete/Remove/Clear` | `[HttpDelete]` |
173
+ | `Patch` | `[HttpPatch]` |
174
+ | 其他 | `[HttpPost]`(默认) |
175
+
176
+ ### 5.1.7.4 路由地址默认约定
177
+
178
+ - 默认以 `api` 开头
179
+ - 默认转换为小写路由地址
180
+ - 控制器路由模板格式:`api/前置参数列表/模块名或默认区域名/[controller@版本号]/后置参数列表`
181
+ - 动作方法路由模板格式:`前置参数列表/模块名/[action@版本号]/后置参数列表`
182
+
183
+ ### 5.1.7.5 其他约定
184
+
185
+ - 默认不处理 `ControllerBase` 控制器类型(支持自定义配置)
186
+ - 默认不处理 GET、HEAD 请求的引用类型参数(支持自定义配置)
187
+
188
+ ---
189
+
190
+ ## 5.1.8 更多例子
191
+
192
+ ### 5.1.8.1 多种请求谓词方法
193
+
194
+ ```csharp
195
+ public class FurionAppService : IDynamicApiController
196
+ {
197
+ public string Get() => "GET 请求";
198
+ public string Post() => "POST 请求";
199
+ public string Delete() => "DELETE 请求";
200
+ public string Put() => "PUT 请求";
201
+ public string Patch() => "PATCH 请求";
202
+ }
203
+ ```
204
+
205
+ ### 5.1.8.2 多个自定义动作方法
206
+
207
+ ```csharp
208
+ public class FurionAppService : IDynamicApiController
209
+ {
210
+ public string GetVersion() => "v1.0.0";
211
+ public string ChangeProfile() => "修改成功";
212
+ public string DeleteUser() => "删除成功";
213
+ }
214
+ ```
215
+
216
+ ### 5.1.8.3 带参数动作方法
217
+
218
+ ```csharp
219
+ public class FurionAppService : IDynamicApiController
220
+ {
221
+ public string GetUser(int id) => $"{id}";
222
+ public string GetUser(int id, string name) => $"{id} {name}";
223
+ public TestDto Add(TestDto testDto) => testDto;
224
+ }
225
+ ```
226
+
227
+ ### 5.1.8.4 GET/HEAD 类类型参数
228
+
229
+ 默认情况下,ASP.NET Core 会将 GET/HEAD 请求中的类类型参数设置为 `[FromBody]` 绑定,但 GET、HEAD 请求不支持 From Body 绑定。
230
+
231
+ 两种解决方式:
232
+
233
+ **方式一:`[FromQuery]` 特性**
234
+
235
+ ```csharp
236
+ public class FurionAppService : IDynamicApiController
237
+ {
238
+ public TestDto GetTest([FromQuery] TestDto testDto) => testDto;
239
+ }
240
+ ```
241
+
242
+ **方式二:配置 `DynamicApiControllerSettings`**(见 5.1.10 节的 `ModelToQuery` 配置)
243
+
244
+ ### 5.1.8.5 自定义参数位置
245
+
246
+ 通过 `[ApiSeat]` 可配置参数在路由中的位置:
247
+
248
+ | 值 | 说明 |
249
+ |----|------|
250
+ | `ApiSeats.ControllerStart` | 控制器之前 |
251
+ | `ApiSeats.ControllerEnd` | 控制器之后 |
252
+ | `ApiSeats.ActionStart` | 动作方法之前 |
253
+ | `ApiSeats.ActionEnd` | 动作方法之后(默认值) |
254
+
255
+ ```csharp
256
+ public class FurionAppService : IDynamicApiController
257
+ {
258
+ public string RouteSeat(
259
+ [ApiSeat(ApiSeats.ControllerStart)] int id,
260
+ [ApiSeat(ApiSeats.ControllerEnd)] string name,
261
+ [ApiSeat(ApiSeats.ActionStart)] decimal weight,
262
+ [ApiSeat(ApiSeats.ActionEnd)] DateTime birthday)
263
+ {
264
+ return "配置路由参数位置";
265
+ }
266
+ }
267
+ ```
268
+
269
+ > **特别注意**:`[ApiSeat]` 只能应用于贴了 `[FromRoute]` 特性的参数或基元类型、值类型、可空基元类型和可空值类型。
270
+
271
+ ### 5.1.8.6 自定义请求谓词
272
+
273
+ ```csharp
274
+ public class FurionAppService : IDynamicApiController
275
+ {
276
+ [HttpPost]
277
+ public string GetVersion() => "1.0.0";
278
+ }
279
+ ```
280
+
281
+ ### 5.1.8.7 支持多个谓词
282
+
283
+ ```csharp
284
+ public class FurionAppService : IDynamicApiController
285
+ {
286
+ [HttpPost, HttpGet, AcceptVerbs("PUT", "DELETE")]
287
+ public string GetVersion() => "1.0.0";
288
+ }
289
+ ```
290
+
291
+ > ⚠️ 如果动作方法中含有类类型参数,且含有 POST/PUT/DELETE 任意请求谓词,那么该参数会自动添加 `[FromBody]`,即使在 GET/HEAD 请求中不支持。
292
+
293
+ ### 5.1.8.8 支持自定义路由
294
+
295
+ ```csharp
296
+ // 自定义控制器路由
297
+ [Route("customapi/mobile/[controller]")]
298
+ public class FurionAppService : IDynamicApiController
299
+ {
300
+ public string GetVersion() => "1.0.0";
301
+ }
302
+ ```
303
+
304
+ > **小提示**:动作方法自定义路由如果以 `/` 开头,则不会合并控制器路由。推荐使用 `[controller]` 或 `[action]` 占位符。
305
+
306
+ ### 5.1.8.9 多路由随意组合
307
+
308
+ ```csharp
309
+ [Route("api/[controller]")]
310
+ [Route("api/[controller]/second")]
311
+ [Route("api/[controller]/three")]
312
+ public class FurionAppService : IDynamicApiController
313
+ {
314
+ [HttpGet]
315
+ [HttpGet("get/[action]")]
316
+ [HttpPost]
317
+ [HttpPost("post/cus-version")]
318
+ public string GetVersion() => "1.0.0";
319
+ }
320
+ ```
321
+
322
+ > ⚠️ 动作方法不能同时贴 `[Route]` 和 `[HttpMethod]` 特性,只能二取一。
323
+
324
+ ### 5.1.8.10 支持版本控制
325
+
326
+ ```csharp
327
+ public class FurionAppServiceV1 : IDynamicApiController
328
+ {
329
+ public string Get() => nameof(Furion);
330
+ }
331
+
332
+ public class FurionAppServiceV1_2 : IDynamicApiController
333
+ {
334
+ public string Get() => nameof(Furion);
335
+ }
336
+
337
+ public class FurionAppServiceV1_2_1 : IDynamicApiController
338
+ {
339
+ public string Get() => nameof(Furion);
340
+ }
341
+ ```
342
+
343
+ > **版本生成原理**:`V[0-9_]` 结尾的命名自动解析成版本号,如 `FurionAppServiceV2` → `v2/Furion`。
344
+
345
+ 版本复写:
346
+
347
+ ```csharp
348
+ [ApiDescriptionSettings(Version = "4.0")]
349
+ public string GetV1() => nameof(Furion);
350
+ ```
351
+
352
+ ### 5.1.8.11 不公开控制器或动作方法
353
+
354
+ ```csharp
355
+ public class FurionAppService : IDynamicApiController
356
+ {
357
+ public string Export() { /* .... */ }
358
+
359
+ [ApiDescriptionSettings(false)] // 不在 Swagger 上显示
360
+ public string NoExport() { /* ... */ }
361
+
362
+ [ApiDescriptionSettings(IgnoreApi = true)] // 不在 Swagger 上显示
363
+ public string NoExport2() { /* ... */ }
364
+
365
+ [NonAction] // 不是一个 API
366
+ public string IsNotAPI() { /* ... */ }
367
+ }
368
+
369
+ [ApiDescriptionSettings(false)] // 不导出整个控制器
370
+ public class NoExportServices : IDynamicApiController { }
371
+
372
+ [NonController] // 标记不是一个控制器
373
+ public class TestController : ControllerBase { }
374
+ ```
375
+
376
+ ### 5.1.8.12 保持控制器和方法命名
377
+
378
+ ```json
379
+ {
380
+ "DynamicApiControllerSettings": {
381
+ "KeepName": true,
382
+ "KeepVerb": true,
383
+ "LowercaseRoute": false
384
+ }
385
+ }
386
+ ```
387
+
388
+ ### 5.1.8.13 方法参数 [FromQuery] 化
389
+
390
+ ```csharp
391
+ [QueryParameters]
392
+ public string Get(int id, string name)
393
+ {
394
+ return $"{id} {name}";
395
+ }
396
+ // 生成的路由为:https://xxx.com?id=1&name=Furion
397
+ ```
398
+
399
+ 全局配置(只影响基元类型参数):
400
+
401
+ ```json
402
+ {
403
+ "DynamicApiControllerSettings": {
404
+ "UrlParameterization": true
405
+ }
406
+ }
407
+ ```
408
+
409
+ > ⚠️ 贴了 `[QueryParameters]` 之后会对所有参数影响,如不需要处理某个参数,只需贴 `[FromXXX]` 特性即可。
410
+
411
+ ### 5.1.8.14 参数绑定配置
412
+
413
+ - `[FromRoute]`:通过路由参数绑定值
414
+ - `[FromQuery]`:通过 Url 地址参数绑定值
415
+ - `[FromBody]`:通过 Request Body 参数绑定值
416
+ - `[FromForm]`:通过表单提交绑定值
417
+ - `[FromHeader]`:通过 Request Header 参数绑定值
418
+
419
+ ### 5.1.8.15 自定义根据方法名生成 [HttpMethod] 规则
420
+
421
+ 在 `appsettings.json` 中配置:
422
+
423
+ ```json
424
+ {
425
+ "DynamicApiControllerSettings": {
426
+ "VerbToHttpMethods": [
427
+ ["getall", "HEAD"],
428
+ ["other", "PUT"]
429
+ ]
430
+ }
431
+ }
432
+ ```
433
+
434
+ > ⚠️ 二维数组中每个元素的第一个必须**全小写**,第二个必须**全大写**,取值有:`HEAD`、`GET`、`PUT`、`POST`、`PATCH`、`DELETE`。
435
+
436
+ ### 5.1.8.16 路由参数非必填/选填
437
+
438
+ ```csharp
439
+ // 方式一:可空 ?
440
+ public object Method1(int id, DateTime? dateTime) { }
441
+
442
+ // 方式二:默认值
443
+ public object Method1(int id, int age = 10) { }
444
+
445
+ // 方式三:默认值 + 可空 ?
446
+ public object Method1(int id, int? age = 10) { }
447
+
448
+ // 方式四:[FromQuery] 修饰
449
+ public object Method1(int id, [FromQuery] string keyword) { }
450
+ ```
451
+
452
+ ### 5.1.8.17 [FromRoute] 路由约束
453
+
454
+ 通过 `[RouteConstraint]` 特性配置路由约束:
455
+
456
+ ```csharp
457
+ public object Method1([RouteConstraint(":min(10)")] int id) { }
458
+ ```
459
+
460
+ 支持的路由约束符号:
461
+
462
+ | 符号 | 描述 | 例子 |
463
+ |------|------|------|
464
+ | `*` | 匹配路由 0-n 长度(4.8.6.2+) | `:*` |
465
+ | `alpha` | 匹配拉丁字母字符 | `:alpha` |
466
+ | `bool` | bool 类型 | `:bool` |
467
+ | `datetime` | DateTime 类型 | `:datetime` |
468
+ | `decimal` | decimal 类型 | `:decimal` |
469
+ | `double` | double 类型 | `:double` |
470
+ | `float` | float 类型 | `:float` |
471
+ | `guid` | guid 类型 | `:guid` |
472
+ | `int` | int 类型 | `:int` |
473
+ | `long` | long 类型 | `:long` |
474
+ | `length` | 匹配长度 | `:length(6)` 或 `:length(1,20)` |
475
+ | `max` | 最大值 | `:max(10)` |
476
+ | `maxlength` | 最大长度 | `:maxlength(10)` |
477
+ | `min` | 最小值 | `:min(10)` |
478
+ | `minlength` | 最小长度 | `:minlength(10)` |
479
+ | `range` | 取值范围 | `:range(10,50)` |
480
+ | `regex` | 正则表达式 | `:regex(^\d{3}-\d{3}-\d{4}$)` |
481
+
482
+ ### 5.1.8.18 小驼峰路由路径
483
+
484
+ ```json
485
+ {
486
+ "DynamicApiControllerSettings": {
487
+ "LowercaseRoute": false,
488
+ "KeepName": true,
489
+ "AsLowerCamelCase": true
490
+ }
491
+ }
492
+ ```
493
+
494
+ ### 5.1.8.19 application/xml 报文参数支持
495
+
496
+ 在 `Startup.cs` 中启用 XML 请求报文格式支持:
497
+
498
+ ```csharp
499
+ services.AddControllers()
500
+ .AddXmlSerializerFormatters()
501
+ .AddXmlDataContractSerializerFormatters();
502
+ ```
503
+
504
+ > 如果出现 `XmlSerializer` 异常,移除 `.AddXmlSerializerFormatters()` 即可。
505
+
506
+ 在动态 WebAPI 中使用:
507
+
508
+ ```csharp
509
+ public class XmlDemo : IDynamicApiController
510
+ {
511
+ //[Consumes("application/xml")] // 设置了则只能传递 XML 格式,不设置则支持多种
512
+ public People Test(People people) => people;
513
+ }
514
+ ```
515
+
516
+ > **`[Consumes]` 和 `[Produces]` 说明**:`[Consumes]` 定义输入参数格式(对应请求报文的 accept),`[Produces]` 定义返回值格式(对应响应报文的 content-type)。
517
+
518
+ ### 5.1.8.20 监听请求取消 CancellationToken 参数
519
+
520
+ > **版本说明**:Furion 4.9.2.19+ 版本使用。
521
+
522
+ ```csharp
523
+ [HttpGet]
524
+ public async Task SomeApi(CancellationToken cancellationToken)
525
+ {
526
+ cancellationToken.Register(() =>
527
+ {
528
+ Console.WriteLine("用户中断了请求。");
529
+ });
530
+
531
+ await Task.Run(() => { /* 模拟异步操作 */ }, cancellationToken);
532
+ }
533
+ ```
534
+
535
+ ### 5.1.8.21 忽略参数绑定(生成路由)
536
+
537
+ > **版本说明**:Furion 4.9.2.25+ 版本使用。
538
+
539
+ ```csharp
540
+ public void TestBindNever([BindNever] string never, int id) { }
541
+ ```
542
+
543
+ 忽略某个类型的属性:
544
+
545
+ ```csharp
546
+ [Newtonsoft.Json.JsonIgnore] // 针对 Newtonsoft
547
+ [System.Text.Json.Serialization.JsonIgnore] // 针对 System.Text.Json
548
+ public string PropertyName { get; set; }
549
+ ```
550
+
551
+ ### 5.1.8.22 绑定数组类型 URL 参数
552
+
553
+ > **版本说明**:Furion 4.9.3.5+ 版本使用。
554
+
555
+ ```csharp
556
+ public void GetArray([FromQuery] [FlexibleArray<string>] List<string> status) { }
557
+ ```
558
+
559
+ 支持 `status[]=a&status[]=b` 和 `status=a,b` 两种格式。`FlexibleArray` 的泛型类型 `T` 为数组元素的类型,支持在属性和参数上标注。
560
+
561
+ ---
562
+
563
+ ## 5.1.9 [ApiDescriptionSettings]
564
+
565
+ ### 5.1.9.1 内置配置
566
+
567
+ | 属性 | 类型 | 默认值 | 说明 |
568
+ |------|------|--------|------|
569
+ | `Name` | string | null | 自定义控制器/动作方法名称 |
570
+ | `KeepName` | bool | false | 是否保持原有名称不处理 |
571
+ | `SplitCamelCase` | bool | true | 切割骆驼/帕斯卡命名 |
572
+ | `KeepVerb` | bool | false | 是否保留动作方法请求谓词 |
573
+ | `Enabled` | bool | true | 是否导出接口 |
574
+ | `Module` | string | null | 模块名 |
575
+ | `Version` | string | null | 版本号 |
576
+ | `Groups` | string[] | null | 接口分组,可结合 Swagger 使用 |
577
+ | `Tags` | string[] | null | 接口标签,可结合 Swagger 使用 |
578
+ | `Order` | int | 0 | 配置排序,数值越大越靠前 |
579
+ | `LowercaseRoute` | bool | true | 是否采用小写路由 |
580
+ | `AsLowerCamelCase` | bool | false | 启用小驼峰命名(首字母小写) |
581
+ | `Area` | string | 空 | 配置区域名称,只作用于类 |
582
+ | `Description` | string | null | 更多描述功能,只在方法中有效(v3.3.5+) |
583
+ | `ForceWithRoutePrefix` | bool | false | 是否强制添加 DefaultRoutePrefix(v3.4.1+) |
584
+ | `DisableInherite` | bool | false | 是否被派生类继承时生成路由(4.9.5.8+) |
585
+
586
+ ### 5.1.9.2 ~ 5.1.9.10 各配置示例
587
+
588
+ **Name 配置:**
589
+
590
+ ```csharp
591
+ [ApiDescriptionSettings(Name = "MyFur")]
592
+ public class FurionAppService : IDynamicApiController
593
+ {
594
+ [ApiDescriptionSettings(Name = "MyGet")]
595
+ public string Get() => nameof(Furion);
596
+ }
597
+ ```
598
+
599
+ **KeepName 配置:** 保留原有的控制器或动作方法名称。
600
+
601
+ **SplitCamelCase 配置:** 默认将骆驼命名切割成多个单词并通过 `-` 连接。`KeepName` 优先级高于 `SplitCamelCase`。
602
+
603
+ **KeepVerb 配置:** 标识是否保留动作谓词。
604
+
605
+ **Enabled 配置:** `[ApiDescriptionSettings(false)]` 不导出接口。
606
+
607
+ **Module 配置:** 配置路由分离,类似于 Mvc 区域的作用。
608
+
609
+ ```csharp
610
+ [ApiDescriptionSettings(Module = "mobile")]
611
+ public class FurionAppService : IDynamicApiController
612
+ {
613
+ [ApiDescriptionSettings(Module = "user")]
614
+ public string GetVersion() => nameof(Furion);
615
+ }
616
+ ```
617
+
618
+ **Version 配置:** 配置接口版本,可复写特殊版本命名配置。默认版本分隔符为 `@`。
619
+
620
+ **Groups 配置:** 配置 Swagger 分组信息,将控制器和动作方法进行归类和多个分组共享。
621
+
622
+ **Tag 配置:** 配置 Swagger 标签分组信息及合并标签(组中组)。如果 `Tag` 名字一样则会自动合并。
623
+
624
+ ---
625
+
626
+ ## 5.1.10 DynamicApiControllerSettings 配置
627
+
628
+ | 配置项 | 类型 | 默认值 | 说明 |
629
+ |--------|------|--------|------|
630
+ | `DefaultRoutePrefix` | string | `api` | 默认路由前缀 |
631
+ | `DefaultHttpMethod` | string | `POST` | 默认请求谓词 |
632
+ | `DefaultModule` | string | null | 默认模块名称(区域) |
633
+ | `LowercaseRoute` | bool | true | 小写路由格式 |
634
+ | `AsLowerCamelCase` | bool | false | 启用小驼峰命名 |
635
+ | `KeepVerb` | bool | false | 是否保留动作谓词 |
636
+ | `KeepName` | bool | false | 是否保留默认名称 |
637
+ | `CamelCaseSeparator` | string | `-` | 骆驼命名分隔符 |
638
+ | `VersionSeparator` | string | `v`(4.9.1.14+ 之前为 `@`) | 版本分隔符 |
639
+ | `VersionInFront` | bool | true | 版本号是否在前面(4.9.1.14+) |
640
+ | `ModelToQuery` | bool | false | GET/HEAD 类类型参数转查询参数 |
641
+ | `SupportedMvcController` | bool | false | 是否支持 Mvc Controller 动态配置 |
642
+ | `UrlParameterization` | bool | false | 路由参数采用 [FromQuery] 化 |
643
+ | `DefaultArea` | string | null | 配置默认区域 |
644
+ | `ForceWithRoutePrefix` | bool | false | 强制添加 DefaultRoutePrefix(v3.4.1+) |
645
+ | `AbandonControllerAffixes` | string[] | `AppServices, AppService, ApiController, Controller, Services, Service` | 去除控制器名称前后缀列表 |
646
+ | `AbandonActionAffixes` | string[] | `Async` | 去除动作方法名称前后缀列表 |
647
+ | `VerbToHttpMethods` | string[][] | 内置规则 | 复写方法名转 HttpMethod 规则 |
648
+ | `DefaultBindingInfo` | string | `route` | 默认基元参数绑定方式(4.9.2.32+) |
649
+
650
+ ### 5.1.10.1 支持 Mvc 控制器动态配置
651
+
652
+ ```json
653
+ {
654
+ "DynamicApiControllerSettings": {
655
+ "SupportedMvcController": true
656
+ }
657
+ }
658
+ ```
659
+
660
+ > **注意事项**:启用该配置后,如果 Mvc 控制器没有任何 `[Route]` 特性但贴了 `[ApiController]` 特性将会报错。建议使用 `[ApiDataValidation]` 代替。
661
+
662
+ ---
663
+
664
+ ## 5.1.11 关于 AOP 拦截
665
+
666
+ 动态 WebAPI 支持 Controller 的所有过滤器/筛选器拦截:
667
+
668
+ ```csharp
669
+ public class SampleAsyncActionFilter : IAsyncActionFilter
670
+ {
671
+ public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
672
+ {
673
+ // 拦截之前
674
+ var resultContext = await next();
675
+ // 拦截之后
676
+
677
+ if (resultContext.Exception != null)
678
+ {
679
+ // 异常拦截
680
+ }
681
+ }
682
+ }
683
+ ```
684
+
685
+ ---
686
+
687
+ ## 5.1.12 设置 api 超时请求时间
688
+
689
+ **.NET5 版本:**
690
+
691
+ ```csharp
692
+ webBuilder.UseKestrel(option =>
693
+ {
694
+ option.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(20);
695
+ option.Limits.RequestHeadersTimeout = TimeSpan.FromMinutes(20);
696
+ });
697
+ ```
698
+
699
+ **.NET6 版本:**
700
+
701
+ ```csharp
702
+ app.Configuration.Get<WebHostBuilder>().ConfigureKestrel(x =>
703
+ {
704
+ x.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(20);
705
+ x.Limits.RequestHeadersTimeout = TimeSpan.FromMinutes(20);
706
+ });
707
+ ```
708
+
709
+ ---
710
+
711
+ ## 5.1.13 获取路由/控制器/Action 列表
712
+
713
+ **获取当前路由表信息:**
714
+
715
+ ```csharp
716
+ var routeValuesFeature = _httpContextAccessor.HttpContext.Features.Get<IRouteValuesFeature>();
717
+ var routeValues = routeValuesFeature.RouteValues;
718
+ ```
719
+
720
+ **获取当前终点路由信息:**
721
+
722
+ ```csharp
723
+ var endpointFeature = _httpContextAccessor.HttpContext.Features.Get<IEndpointFeature>();
724
+ var routeEndpoint = endpointFeature.Endpoint as RouteEndpoint;
725
+ var routePattern = routeEndpoint.RoutePattern;
726
+ var metadata = routeEndpoint.Metadata;
727
+ ```
728
+
729
+ **获取所有控制器列表:**
730
+
731
+ ```csharp
732
+ var controllerFeature = new ControllerFeature();
733
+ _applicationPartManager.PopulateFeature(controllerFeature);
734
+ IList<TypeInfo> controllers = controllerFeature.Controllers;
735
+ ```
736
+
737
+ **获取所有 Action 列表:**
738
+
739
+ ```csharp
740
+ var actionDescriptors = _actionDescriptorCollectionProvider.ActionDescriptors.Items;
741
+
742
+ foreach (ActionDescriptor actionDescriptor in actionDescriptors)
743
+ {
744
+ var method = (actionDescriptor as ControllerActionDescriptor).MethodInfo;
745
+ var route = actionDescriptor.AttributeRouteInfo.Template;
746
+ var httpMethod = actionDescriptor.ActionConstraints?.OfType<HttpMethodActionConstraint>()
747
+ .FirstOrDefault()?.HttpMethods.First();
748
+ }
749
+ ```
750
+
751
+ **获取所有 Action 列表带分组信息:**
752
+
753
+ ```csharp
754
+ var apiDescriptionGroups = _apiDescriptionGroupCollectionProvider.ApiDescriptionGroups.Items;
755
+
756
+ foreach (ApiDescriptionGroup group in apiDescriptionGroups)
757
+ {
758
+ foreach (ApiDescription action in group.Items)
759
+ {
760
+ var route = action.RelativePath;
761
+ var httpMethod = action.HttpMethod;
762
+ var groupName = action.GroupName;
763
+ }
764
+ }
765
+ ```
766
+
767
+ ---
768
+
769
+ ## 5.1.14 插件化 IDynamicApiRuntimeChangeProvider
770
+
771
+ > **版本说明**:Furion 4.8.8.8+ 版本使用。
772
+
773
+ 在运行时动态编译代码并添加为 WebAPI:
774
+
775
+ ```csharp
776
+ public class PluginApiServices : IDynamicApiController
777
+ {
778
+ private readonly IDynamicApiRuntimeChangeProvider _provider;
779
+
780
+ public PluginApiServices(IDynamicApiRuntimeChangeProvider provider)
781
+ {
782
+ _provider = provider;
783
+ }
784
+
785
+ public string Compile([FromBody] string csharpCode, [FromQuery] string assemblyName = default)
786
+ {
787
+ var dynamicAssembly = App.CompileCSharpClassCode(csharpCode, assemblyName);
788
+ _provider.AddAssembliesWithNotifyChanges(dynamicAssembly);
789
+ return dynamicAssembly.GetName().Name;
790
+ }
791
+
792
+ public void Remove(string assemblyName)
793
+ {
794
+ _provider.RemoveAssembliesWithNotifyChanges(assemblyName);
795
+ }
796
+ }
797
+ ```
798
+
799
+ 请求 `api/plugin-api/compile` 接口并设置 `Content-Type` 为 `text/plain`,传入 C# 代码字符串即可。刷新浏览器即可看到最新的 API。
800
+
801
+ ---
802
+
803
+ ## 5.1.15 自定义生成 API 规则
804
+
805
+ ```csharp
806
+ services.ConfigureDynamicApiController(builder =>
807
+ {
808
+ // 自定义控制器生成逻辑
809
+ builder.ControllerFilter = (type) =>
810
+ {
811
+ return type != typeof(PersonService); // 排除特定类型
812
+ };
813
+
814
+ // 自定义 Action 生成配置
815
+ builder.ActionConfigure = (actionModel) =>
816
+ {
817
+ if (actionModel.ActionMethod.Name == "Insert")
818
+ {
819
+ actionModel.ApiExplorer.IsVisible = false;
820
+ }
821
+ };
822
+ });
823
+ ```
824
+
825
+ > **注意**:请确保在 `AddInject()` 或 `AddDynamicApiControllers` 之前注册。