@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,1458 @@
1
+ # 6. 规范化接口文档
2
+
3
+ ## 📝 模块更新日志
4
+
5
+ *(详见 Furion 官方 Changelog)*
6
+
7
+ ---
8
+
9
+ ## 6.1 什么是接口文档
10
+
11
+ 在现在移动为王、多端互辅、前端百花齐放的开放时代,不再是一人包揽式开发,大家各司其职,后端工程师负责接口开发,前端负责接口联调,也就是互联网现在流行的前后端分离架构。
12
+
13
+ 所以就需要由前后端工程师共同定义接口,编写接口文档,之后大家按照这个接口文档进行开发、维护及开放给第三方。
14
+
15
+ ## 6.2 为什么要写接口文档
16
+
17
+ - 能够让前端开发与后台开发人员更好的配合,提高工作效率
18
+ - 项目迭代或者项目人员更迭时,方便后期人员查看和维护
19
+ - 方便测试人员进行接口测试
20
+
21
+ ## 6.3 为什么需要规范化文档
22
+
23
+ 由于每个公司后端人员技术参差不齐,技术文档能力也不例外,导致接口定义及文档五花八门,不同项目或不同公司对接极其困难,而且体验糟糕。所以,无规矩不成方圆,为了开发人员间更好的配合,迫切需要整理出一套规范。
24
+
25
+ 通常接口规范分为六个部分:
26
+
27
+ ### 6.3.1 协议规范
28
+
29
+ 为了确保不同系统/模块间的数据交互,需要事先约定好通讯协议,如:TCP、HTTP、HTTPS 协议。为了确保数据交互安全,建议使用 HTTPS 协议。
30
+
31
+ ### 6.3.2 接口路径规范
32
+
33
+ 作为接口路径,为了方便清晰的区分来自不同的系统,可以采用不同系统/模块名作为接口路径前缀,如:支付模块 `/pay/xxx`,订单模块 `/order/xxx`。
34
+
35
+ ### 6.3.3 版本控制规范
36
+
37
+ 为了便于后期接口的升级和维护,建议在接口路径中加入版本号,便于管理,实现接口多版本的可维护性。如:接口路径中添加类似 `v1`、`v2` 等版本号。
38
+
39
+ ### 6.3.4 接口命名规范
40
+
41
+ 和 C# 命名规范一样,好的、统一的接口命名规范,不仅可以增强其可读性,而且还会减少很多不必要的口头/书面上的解释。可使用"驼峰命名法"按照实现接口的业务类型、业务场景等命名。
42
+
43
+ 常见命名方式:
44
+
45
+ **接口名称动词前/后缀化:** 接口名称以接口数据操作的动词为前/后缀,常见动词有:Add、Delete、Update、Query、Get、Send、Save、Detail、List 等,如:新建用户 `AddUser`、查询订单详情 `QueryOrderDetail`。
46
+
47
+ **接口名称动词 + 请求方式:** 接口路径中包含具体接口名称的名词,接口数据操作动作以 HTTP 请求方式来区分:
48
+
49
+ | 方法 | 说明 |
50
+ |------|------|
51
+ | GET | 从服务器取出资源(一项或多项) |
52
+ | POST | 在服务器新建一个资源 |
53
+ | PUT | 在服务器更新资源(客户端提供改变后的完整资源) |
54
+ | PATCH | 在服务器更新资源(客户端提供改变的属性) |
55
+ | DELETE | 从服务器删除资源 |
56
+
57
+ ### 6.3.5 请求参数规范
58
+
59
+ - **请求方式**:按照 GET、POST、PUT 等含义定义,避免出现不一致现象
60
+ - **请求头**:请求头根据项目需求添加配置参数。如:请求数据格式 `accept=application/json` 等。如有需要,请求头可根据项目需求要求传入用户 token、唯一验签码等加密数据
61
+ - **请求参数/请求体**:请求参数字段,尽可能与数据库表字段、对象属性名等保持一致
62
+
63
+ ### 6.3.6 返回数据规范
64
+
65
+ 统一规范返回数据的格式,以 JSON 格式为例。返回数据应包含:返回状态码、返回状态信息、具体数据。返回数据中的状态码、状态信息,常指具体的业务状态,不建议和 HTTP 状态码混在一起。HTTP 状态码和 JSON 结果中的状态码,并存尚可,用于体现不同维度的状态。
66
+
67
+ ---
68
+
69
+ ## 6.4 什么是 Swagger
70
+
71
+ Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。
72
+
73
+ 通过这套规范,你只需要按照它的规范去定义接口及接口相关的信息。再通过 Swagger 衍生出来的一系列项目和工具,就可以做到生成各种格式的接口文档,生成多种语言的客户端和服务端的代码,以及在线接口调试页面等等。
74
+
75
+ 总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法、参数和模型紧密集成到服务器端的代码,允许 API 来始终保持同步。
76
+
77
+ ---
78
+
79
+ ## 6.5 Swagger 使用
80
+
81
+ Furion 框架提供了非常方便且灵活的 Swagger 配置,无需增加额外学习成本。
82
+
83
+ ### 6.5.1 注册服务
84
+
85
+ > **小提示**:`.AddInject[XXX]()` 已经包含了 `.AddSpecificationDocuments()` 注册,无需再次注册。`.UseInject()` 已经包含了 `.UseSpecificationDocuments()` 注册,无需再次注册。
86
+
87
+ ```csharp
88
+ // Furion.Web.Core\Startup.cs
89
+ using Microsoft.AspNetCore.Builder;
90
+ using Microsoft.AspNetCore.Hosting;
91
+ using Microsoft.Extensions.DependencyInjection;
92
+ using Microsoft.Extensions.Hosting;
93
+
94
+ namespace Furion.Web.Core
95
+ {
96
+ [AppStartup(800)]
97
+ public sealed class FurWebCoreStartup : AppStartup
98
+ {
99
+ public void ConfigureServices(IServiceCollection services)
100
+ {
101
+ services.AddSpecificationDocuments();
102
+ services.AddControllers();
103
+ }
104
+
105
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
106
+ {
107
+ // Other Codes
108
+
109
+ app.UseSpecificationDocuments();
110
+
111
+ app.UseEndpoints(endpoints =>
112
+ {
113
+ endpoints.MapControllers();
114
+ });
115
+ }
116
+ }
117
+ }
118
+ ```
119
+
120
+ > **小知识**:`services.AddSpecificationDocuments()` 通常和 `.AddDynamicApiControllers()` 成对出现。
121
+
122
+ ### 6.5.2 默认地址
123
+
124
+ 在 Furion 框架中,默认规范化文档地址为 `/api` 目录,支持自定义配置。
125
+
126
+ 可以通过两种方式配置:
127
+
128
+ **方式一:`app.UseInject("路由")`**
129
+
130
+ ```csharp
131
+ app.UseInject("testapi"); // 那么 /testapi 就是规范化地址
132
+ ```
133
+
134
+ **方式二:配置文件**
135
+
136
+ ```json
137
+ {
138
+ "SpecificationDocumentSettings": {
139
+ "RoutePrefix": "testapi"
140
+ }
141
+ }
142
+ ```
143
+
144
+ > 配置文件优先级大于 `UseInject()` 方式。
145
+
146
+ ### 6.5.3 默认分组
147
+
148
+ Furion 框架中默认分组名为 `Default`,支持自定义配置:
149
+
150
+ ```json
151
+ {
152
+ "SpecificationDocumentSettings": {
153
+ "DefaultGroupName": "MyGroup"
154
+ }
155
+ }
156
+ ```
157
+
158
+ ### 6.5.4 文档注释
159
+
160
+ 规范化文档默认扫描 `Furion.Application`、`Furion.Web.Core`、`Furion.Web.Entry` 三个程序集 `.xml` 注释文件,支持自定义配置。
161
+
162
+ 只支持 `///` 标识的注释语法,如:类、方法、属性、参数、返回值、验证特性。
163
+
164
+ ```csharp
165
+ using Furion.DynamicApiController;
166
+
167
+ namespace Furion.Application
168
+ {
169
+ /// <summary>
170
+ /// 类注释
171
+ /// </summary>
172
+ public class FurionAppService : IDynamicApiController
173
+ {
174
+ /// <summary>
175
+ /// 方法注释
176
+ /// </summary>
177
+ /// <returns></returns>
178
+ public string Get()
179
+ {
180
+ return nameof(Furion);
181
+ }
182
+
183
+ /// <summary>
184
+ /// 带 ID 参数的方法注释
185
+ /// </summary>
186
+ /// <param name="id"></param>
187
+ /// <returns></returns>
188
+ public int Get(int id)
189
+ {
190
+ return id;
191
+ }
192
+
193
+ [DisplayName("生成注释")] // Furion 4.9.2.3+ 版本支持
194
+ public void SomeMethod()
195
+ {
196
+ }
197
+ }
198
+ }
199
+ ```
200
+
201
+ > **小提示**:如果文档注释没有显示,请检查项目 **属性 → 生成 → 输出** 中 XML 文档是否配置输出路径。注意:只有不带路径的 `【项目名称.xml】` 才会自动加载。
202
+
203
+ ```xml
204
+ <PropertyGroup>
205
+ <TargetFramework>net6.0</TargetFramework>
206
+ <DocumentationFile>Furion.Application.xml</DocumentationFile>
207
+ </PropertyGroup>
208
+ ```
209
+
210
+ > **特别说明**:Debug 模式下和 Release 模式下的注释文件是不通用的,所以导致很多开发者发布到服务器上发现没有显示注释。只需要在 Visual Studio 中切换 Debug 模式为 Release,然后重新配置一次即可。
211
+
212
+ ### 6.5.5 多分组支持
213
+
214
+ 多分组是一个系统中必备功能,我们可以将系统划分为多个模块,每个模块都独立的 api 配置。
215
+
216
+ ```csharp
217
+ using Furion.DynamicApiController;
218
+
219
+ namespace Furion.Application
220
+ {
221
+ [ApiDescriptionSettings("Group1")]
222
+ public class FurionAppService : IDynamicApiController
223
+ {
224
+ /// <summary>
225
+ /// 随父类 Group1 分组
226
+ /// </summary>
227
+ public string Post()
228
+ {
229
+ return nameof(Furion);
230
+ }
231
+
232
+ /// <summary>
233
+ /// 在 Group1、Group3 都有我
234
+ /// </summary>
235
+ [ApiDescriptionSettings("Group1", "Group3")]
236
+ public string Get()
237
+ {
238
+ return nameof(Furion);
239
+ }
240
+
241
+ /// <summary>
242
+ /// 我只在 Group2 出现
243
+ /// </summary>
244
+ [ApiDescriptionSettings("Group2")]
245
+ public int Get(int id)
246
+ {
247
+ return id;
248
+ }
249
+ }
250
+ }
251
+ ```
252
+
253
+ ### 6.5.6 多分组排序
254
+
255
+ 通过分组名称添加 `@整数` 进行排序:
256
+
257
+ ```csharp
258
+ [ApiDescriptionSettings("Group1@1")]
259
+ public class FurionAppService : IDynamicApiController
260
+ {
261
+ public string Post()
262
+ {
263
+ return nameof(Furion);
264
+ }
265
+
266
+ [ApiDescriptionSettings("Group1", "Group3")]
267
+ public string Get()
268
+ {
269
+ return nameof(Furion);
270
+ }
271
+
272
+ [ApiDescriptionSettings("Group@2")]
273
+ public int Get(int id)
274
+ {
275
+ return id;
276
+ }
277
+ }
278
+ ```
279
+
280
+ 可以通过在分组名后面添加 `@整数` 进行排序,**整数越大排前面**。如果分组名称多次指定且多次指定了 `@整数`,则自动取该分组最大的整数进行排序。
281
+
282
+ > **排序说明**:分组默认排序 `Order` 为 0。如果同时配置了 `@整数` 和 `appsettings.json` 配置文件,那么优先采用 `appsettings.json` 中的 `Order`。
283
+
284
+ ### 6.5.7 多分组信息配置
285
+
286
+ Furion 框架提供了可通过 `appsettings.json` 配置分组信息:
287
+
288
+ ```json
289
+ {
290
+ "SpecificationDocumentSettings": {
291
+ "GroupOpenApiInfos": [
292
+ {
293
+ "Group": "Group1",
294
+ "Title": "分组标题",
295
+ "Description": "这里是分组描述",
296
+ "Version": "版本号",
297
+ "TermsOfService": "https://furion.net",
298
+ "Contact": {
299
+ "Name": "百小僧",
300
+ "Url": "https://gitee.com/monksoul",
301
+ "Email": "monksoul@outlook.com"
302
+ },
303
+ "License": {
304
+ "Name": "MIT",
305
+ "Url": "https://gitee.com/dotnetchina/Furion/blob/alpha/LICENSE"
306
+ }
307
+ }
308
+ ]
309
+ }
310
+ }
311
+ ```
312
+
313
+ **版本说明**(Furion 4.8.8.26+):自该版本开始,可以在任何配置文件中添加 `[openapi:分组名]` 作为 Key 进行配置:
314
+
315
+ ```json
316
+ {
317
+ "[openapi:Group1]": {
318
+ "Title": "我是自定义的标题",
319
+ "Order": 10,
320
+ "Description": "我是自定义的描述",
321
+ "Version": "2.0.0",
322
+ "TermsOfService": "https://furion.net",
323
+ "Contact": {
324
+ "Name": "Furion.NET",
325
+ "Url": "https://gitee.com/monksoul",
326
+ "Email": "support@furion.net"
327
+ },
328
+ "License": {
329
+ "Name": "MIT",
330
+ "Url": "https://gitee.com/dotnetchina/Furion/blob/v4/LICENSE"
331
+ }
332
+ }
333
+ }
334
+ ```
335
+
336
+ > 如果两种方式同时配置,那么 `GroupOpenApiInfos` 中的属性值只有在 `[openapi:分组名]` 配置中存在才会覆盖,不存在则保留。
337
+
338
+ ### 6.5.8 控制器和方法排序
339
+
340
+ 框架提供了 `[ApiDescriptionSettings]` 特性的 `Order` 属性,其值越大排序越靠前:
341
+
342
+ ```csharp
343
+ [ApiDescriptionSettings(Order = 10)]
344
+ public class FurionAppService : IDynamicApiController
345
+ {
346
+ public string Post()
347
+ {
348
+ return nameof(Furion);
349
+ }
350
+
351
+ [ApiDescriptionSettings(Order = 5)]
352
+ public string Get()
353
+ {
354
+ return nameof(Furion);
355
+ }
356
+
357
+ [ApiDescriptionSettings(Order = 4)]
358
+ public int Get(int id)
359
+ {
360
+ return id;
361
+ }
362
+ }
363
+
364
+ [ApiDescriptionSettings(Order = 9)]
365
+ public class Furion2AppService : IDynamicApiController
366
+ {
367
+ // ...
368
+ }
369
+ ```
370
+
371
+ > **排序说明**:最终输出到 Swagger 界面时,`FurionAppService` 比 `Furion2AppService` 靠前,而 `FurionAppService` 中定义的方法排序时:`Get > Get(int id) > Post`。
372
+
373
+ ### 6.5.9 组中组(标签)
374
+
375
+ `Tag` 配置主要用于配置 Swagger 标签分组信息及合并标签,也就是"组中组":
376
+
377
+ ```csharp
378
+ [ApiDescriptionSettings(Tag = "分组一")]
379
+ public class FurionAppService : IDynamicApiController
380
+ {
381
+ public string Get()
382
+ {
383
+ return nameof(Furion);
384
+ }
385
+
386
+ public int Get(int id)
387
+ {
388
+ return id;
389
+ }
390
+ }
391
+
392
+ [ApiDescriptionSettings(Tag = "分组二")]
393
+ public class TestAppService : IDynamicApiController
394
+ {
395
+ public string Get()
396
+ {
397
+ return nameof(Furion);
398
+ }
399
+
400
+ public int Get(int id)
401
+ {
402
+ return id;
403
+ }
404
+ }
405
+ ```
406
+
407
+ > **小知识**:如果 `Tag` 名字一样,则会自动合并,否则只是命名。
408
+
409
+ ### 6.5.10 默认展开所有文档
410
+
411
+ ```json
412
+ {
413
+ "SpecificationDocumentSettings": {
414
+ "DocExpansionState": "Full"
415
+ }
416
+ }
417
+ ```
418
+
419
+ `DocExpansionState` 配置说明:
420
+
421
+ | 值 | 说明 |
422
+ |------|------|
423
+ | `List` | 列表式(展开子类),默认值 |
424
+ | `Full` | 完全展开 |
425
+ | `None` | 列表式(不展开子类) |
426
+
427
+ ### 6.5.11 配置文档标题
428
+
429
+ ```json
430
+ {
431
+ "SpecificationDocumentSettings": {
432
+ "DocumentTitle": "我是自定义标题"
433
+ }
434
+ }
435
+ ```
436
+
437
+ ### 6.5.12 授权控制
438
+
439
+ 新版本 Furion 已经默认启用了 Bearer Token 授权配置,无需手动配置,如需手动配置:
440
+
441
+ ```json
442
+ {
443
+ "SpecificationDocumentSettings": {
444
+ "EnableAuthorized": true,
445
+ "SecurityDefinitions": [
446
+ {
447
+ "Id": "Bearer",
448
+ "Type": "Http",
449
+ "Name": "Authorization",
450
+ "Description": "JWT Authorization header using the Bearer scheme.",
451
+ "BearerFormat": "JWT",
452
+ "Scheme": "bearer",
453
+ "In": "Header",
454
+ "Requirement": {
455
+ "Scheme": {
456
+ "Reference": { "Id": "Bearer", "Type": "SecurityScheme" },
457
+ "Accesses": []
458
+ }
459
+ }
460
+ },
461
+ {
462
+ "Id": "basic",
463
+ "Type": "Http",
464
+ "Name": "basic",
465
+ "Description": "Basic Authorization header using the username and password.",
466
+ "Scheme": "basic",
467
+ "In": "Header",
468
+ "Requirement": {
469
+ "Scheme": {
470
+ "Reference": { "Id": "basic", "Type": "SecurityScheme" },
471
+ "Accesses": []
472
+ }
473
+ }
474
+ }
475
+ ]
476
+ }
477
+ }
478
+ ```
479
+
480
+ ### 6.5.13 在线测试
481
+
482
+ Swagger 内置了在线测试功能,可直接在文档界面中测试接口。
483
+
484
+ ### 6.5.14 性能监视 MiniProfiler
485
+
486
+ > **功能移除声明**:以下内容在 Furion 4.9.7.75+ 版本中已移除。
487
+
488
+ 规范化文档默认集成了 MiniProfiler 第三方性能组件,通过该组件可以方便查看请求性能、异常堆栈、数据库操作等信息。
489
+
490
+ > 也可以通过 `appsettings.json` 中 `AppSettings:InjectMiniProfiler` 设为 `false` 关闭。
491
+
492
+ ### 6.5.15 定义接口输出类型
493
+
494
+ ```csharp
495
+ using Furion.DynamicApiController;
496
+ using Microsoft.AspNetCore.Mvc;
497
+
498
+ namespace Furion.Application
499
+ {
500
+ public class FurionAppService : IDynamicApiController
501
+ {
502
+ [ProducesResponseType(201, Type = typeof(TestDto))]
503
+ [ProducesResponseType(400)]
504
+ public string Get()
505
+ {
506
+ return nameof(Furion);
507
+ }
508
+ }
509
+ }
510
+ ```
511
+
512
+ ### 6.5.16 隐藏特定分组
513
+
514
+ ```json
515
+ {
516
+ "SpecificationDocumentSettings": {
517
+ "GroupOpenApiInfos": [
518
+ {
519
+ "Group": "Group1",
520
+ "Visible": false
521
+ }
522
+ ]
523
+ }
524
+ }
525
+ ```
526
+
527
+ ### 6.5.17 中文乱码问题
528
+
529
+ 默认情况下 `.json` 文件并未采用 `utf-8` 编码,所以如果配置中文分组信息就会出现乱码情况,这时候只需要修改 `.json` 文件编码为 `utf-8` 即可。
530
+
531
+ ### 6.5.18 生产环境中关闭 Swagger
532
+
533
+ ```json
534
+ {
535
+ "AppSettings": {
536
+ "InjectSpecificationDocument": false
537
+ }
538
+ }
539
+ ```
540
+
541
+ ### 6.5.19 设置 Example Value 默认值
542
+
543
+ Swagger 会自动根据对象类型输入参数添加 Example Value 默认值,如果我们需要自定义这些默认值,只需要添加 `/// <example>默认值</example>` 注释即可。
544
+
545
+ **属性默认值:**
546
+
547
+ ```csharp
548
+ /// <summary>
549
+ /// 年龄
550
+ /// </summary>
551
+ /// <example>13</example>
552
+ [Required, Range(10, 110)]
553
+ public int Age { get; set; }
554
+ ```
555
+
556
+ **参数默认值:**
557
+
558
+ ```csharp
559
+ /// <summary>
560
+ /// 提交
561
+ /// </summary>
562
+ /// <param name="id" example="1">用户 Id</param>
563
+ public void PostId(int id)
564
+ {
565
+ }
566
+ ```
567
+
568
+ 更多类型默认值设置示例:
569
+
570
+ | 类型 | 示例 |
571
+ |------|------|
572
+ | bool | `/// <example>true</example>` |
573
+ | string | `/// <example>foobar</example>` |
574
+ | number | `/// <example>123</example>` |
575
+ | null | `/// <example>null</example>` |
576
+ | array | `/// <example>[ 1, 2, 3 ]</example>` |
577
+ | 空数组 | `/// <example>&quot;[]&quot;</example>` |
578
+ | 空对象 | `/// <example>&quot;{}&quot;</example>` |
579
+
580
+ > **关于 object 类型输入参数**:默认情况下,Example Value 不会显示 object 类型的对象属性。如果需要强制显示,只需要添加 `/// <example>"object"</example>` 注释即可。
581
+
582
+ ### 6.5.20 自定义 Swagger 配置
583
+
584
+ ```csharp
585
+ public void ConfigureServices(IServiceCollection services)
586
+ {
587
+ services.AddInject(options =>
588
+ {
589
+ options.ConfigureSwaggerGen(gen =>
590
+ {
591
+ // ....
592
+ });
593
+ });
594
+ }
595
+
596
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
597
+ {
598
+ // Furion 4.4.8+ 版本可以 app.UseInject(options => {})
599
+ app.UseInject(configure: options =>
600
+ {
601
+ options.ConfigureSwagger(swg =>
602
+ {
603
+ // ....
604
+ });
605
+
606
+ options.ConfigureSwaggerUI(ui =>
607
+ {
608
+ // ....
609
+ });
610
+ });
611
+ }
612
+ ```
613
+
614
+ ### 6.5.21 配置 Swagger 的 SchemaIds
615
+
616
+ ```csharp
617
+ services.AddControllersWithViews()
618
+ .AddInject(options =>
619
+ {
620
+ options.ConfigureSwaggerGen(gen =>
621
+ {
622
+ gen.CustomSchemaIds(x => x.FullName);
623
+ });
624
+ });
625
+ ```
626
+
627
+ ### 6.5.22 自定义 swagger.json 路由模板
628
+
629
+ ```json
630
+ {
631
+ "SpecificationDocumentSettings": {
632
+ "RouteTemplate": "myapp/{documentName}/xxxx.json"
633
+ }
634
+ }
635
+ ```
636
+
637
+ > `{documentName}` 会在运行时替换为分组名。
638
+
639
+ ### 6.5.23 关于 application/x-www-form-urlencoded 请求
640
+
641
+ 默认情况下,Swagger 并未添加 `application/x-www-form-urlencoded` 支持,如需启用:
642
+
643
+ ```csharp
644
+ [Consumes("application/x-www-form-urlencoded")]
645
+ public async Task<IActionResult> Test([FromForm] TestRequest testRequest)
646
+ {
647
+ // ....
648
+ }
649
+ ```
650
+
651
+ > **特别注意**:参数必须贴 `[FromForm]` 特性。另外请求时将参数按 URL 地址拼接并放在 Body 中请求。
652
+
653
+ ### 6.5.24 Swagger 出现 CORS 问题解决
654
+
655
+ ```json
656
+ {
657
+ "SpecificationDocumentSettings": {
658
+ "HideServers": true
659
+ }
660
+ }
661
+ ```
662
+
663
+ ### 6.5.25 Swagger 出现默认 text/xml/text/plain 参数问题解决
664
+
665
+ 产生此原因有两个必要条件:使用了 `Microsoft.AspNetCore.Mvc.NewtonsoftJson` 包并添加了 `AddNewtonsoftJson()` 注册,且 `.AddNewtonsoftJson()` 写在了 `.AddInjectWithUnifyResult()` 后面。
666
+
667
+ 解决方法:先注册 `.AddNewtonsoftJson()` 再注册规范化结果:
668
+
669
+ ```csharp
670
+ services.AddControllers()
671
+ .AddNewtonsoftJson()
672
+ .AddInjectWithUnifyResult();
673
+ ```
674
+
675
+ 如果配置上述代码之后出现 `application/json-patch+json` 默认在第一位:
676
+
677
+ ```csharp
678
+ services.Configure<MvcOptions>(options =>
679
+ {
680
+ options.InputFormatters.RemoveType(typeof(NewtonsoftJsonPatchInputFormatter));
681
+ });
682
+ ```
683
+
684
+ ### 6.5.26 Swagger 多语言支持
685
+
686
+ 在 Furion 2.9.0+ 版本已经支持了 Swagger 文档地址 `?culture=en-US` 参数多语言转发功能,Swagger 地址带 `?culture=` 参数将自动添加到每一个请求的 api 地址中。
687
+
688
+ ### 6.5.27 自定义逻辑控制 Swagger 每一个 api 可见性
689
+
690
+ ```csharp
691
+ services.AddInject(options =>
692
+ {
693
+ options.ConfigureSwaggerGen(gen =>
694
+ {
695
+ gen.DocInclusionPredicate((currentGroup, apiDescription) =>
696
+ {
697
+ // Furion 内部检查,必须放第一行
698
+ var isShow = SpecificationDocumentBuilder.CheckApiDescriptionInCurrentGroup(currentGroup, apiDescription);
699
+
700
+ // 获取当前方法
701
+ _ = apiDescription.TryGetMethodInfo(out var method);
702
+
703
+ // 有了方法,这里做你想做的事情,isShow 设置 true 可见,设置 false 不可见
704
+
705
+ return isShow;
706
+ });
707
+ });
708
+ });
709
+ ```
710
+
711
+ ### 6.5.28 配置 MVC 控制器支持规范化处理
712
+
713
+ ```json
714
+ {
715
+ "UnifyResultSettings": {
716
+ "SupportMvcController": true
717
+ }
718
+ }
719
+ ```
720
+
721
+ ### 6.5.29 Swagger 刷新记住授权状态
722
+
723
+ 默认情况下,Swagger 刷新浏览器后授权状态将被重置。通过下面代码在**用户登录成功后**调用即可:
724
+
725
+ ```csharp
726
+ _httpContextAccessor.HttpContext.SigninToSwagger("传入 token");
727
+ ```
728
+
729
+ ### 6.5.30 带登录的 Swagger 文档
730
+
731
+ > **版本说明**:仅限 Furion v3.3.3+ 版本使用。
732
+
733
+ 默认情况下,Swagger 是任何人都可以访问的,通过配置 `LoginInfo` 可以添加登录功能:
734
+
735
+ ```json
736
+ {
737
+ "SpecificationDocumentSettings": {
738
+ "LoginInfo": {
739
+ "Enabled": true,
740
+ "CheckUrl": "/Home/CheckUrl",
741
+ "SubmitUrl": "/Home/SubmitUrl",
742
+ "UserName": "admin",
743
+ "Password": "admin",
744
+ "EnableOnProduction": false,
745
+ "DefaultUsername": "admin",
746
+ "DefaultPassword": "admin"
747
+ }
748
+ }
749
+ }
750
+ ```
751
+
752
+ 配置说明:
753
+
754
+ | 字段 | 说明 |
755
+ |------|------|
756
+ | `Enabled` | 是否启用登录授权,默认 false |
757
+ | `CheckUrl` | 检查登录状态的 Url 地址,POST 请求,已授权返回 200,否则返回 401 |
758
+ | `SubmitUrl` | 提交登录的 Url 地址,POST 请求且只有一个 `SpecificationAuth` 类型参数 |
759
+ | `EnableOnProduction` | 是否设置生产环境自动开启(4.9.5.7+) |
760
+ | `DefaultUsername` | 默认用户名(4.9.7.113+) |
761
+ | `DefaultPassword` | 默认密码(4.9.7.113+) |
762
+
763
+ #### Controller(MVC)方式
764
+
765
+ ```csharp
766
+ using Furion.SpecificationDocument;
767
+ using Microsoft.AspNetCore.Authorization;
768
+ using Microsoft.AspNetCore.Mvc;
769
+
770
+ namespace Furion.Web.Entry.Controllers;
771
+
772
+ public class HomeController : Controller
773
+ {
774
+ [HttpPost, AllowAnonymous, NonUnify]
775
+ public int CheckUrl()
776
+ {
777
+ return 401;
778
+ }
779
+
780
+ [HttpPost, AllowAnonymous, NonUnify]
781
+ public int SubmitUrl([FromForm] SpecificationAuth auth)
782
+ {
783
+ var userName = App.Configuration["SpecificationDocumentSettings:LoginInfo:UserName"];
784
+ var password = App.Configuration["SpecificationDocumentSettings:LoginInfo:Password"];
785
+
786
+ if (auth.UserName == userName && auth.Password == password)
787
+ {
788
+ return 200;
789
+ }
790
+ else
791
+ {
792
+ return 401;
793
+ }
794
+ }
795
+ }
796
+ ```
797
+
798
+ #### WebAPI/动态API 方式
799
+
800
+ ```csharp
801
+ using Furion.SpecificationDocument;
802
+
803
+ namespace MyProject.Application;
804
+
805
+ public class SwaggerLoginServices : IDynamicApiController
806
+ {
807
+ [HttpPost, AllowAnonymous, NonUnify]
808
+ public int CheckUrl()
809
+ {
810
+ return 401;
811
+ }
812
+
813
+ [HttpPost, AllowAnonymous, NonUnify]
814
+ public int SubmitUrl([FromForm] SpecificationAuth auth)
815
+ {
816
+ var userName = App.Configuration["SpecificationDocumentSettings:LoginInfo:UserName"];
817
+ var password = App.Configuration["SpecificationDocumentSettings:LoginInfo:Password"];
818
+
819
+ if (auth.UserName == userName && auth.Password == password)
820
+ {
821
+ return 200;
822
+ }
823
+ else
824
+ {
825
+ return 401;
826
+ }
827
+ }
828
+ }
829
+ ```
830
+
831
+ ### 6.5.31 inheritdoc 实现注释继承
832
+
833
+ > **版本说明**:仅限 Furion v3.3.3+ 版本使用。
834
+
835
+ ```csharp
836
+ using Furion.DynamicApiController;
837
+
838
+ namespace Furion.Application
839
+ {
840
+ /// <inheritdoc cref="ITestInheritdoc" />
841
+ public class TestInheritdoc : ITestInheritdoc, IDynamicApiController
842
+ {
843
+ /// <inheritdoc cref="ITestInheritdoc.GetName"/>
844
+ public string GetName()
845
+ {
846
+ return "Furion";
847
+ }
848
+
849
+ /// <inheritdoc />
850
+ public string GetVersion()
851
+ {
852
+ return "3.3.3";
853
+ }
854
+ }
855
+
856
+ /// <summary>
857
+ /// 测试注释继承
858
+ /// </summary>
859
+ public interface ITestInheritdoc
860
+ {
861
+ /// <summary>
862
+ /// 获取名称
863
+ /// </summary>
864
+ string GetName();
865
+
866
+ /// <summary>
867
+ /// 获取版本
868
+ /// </summary>
869
+ string GetVersion();
870
+ }
871
+ }
872
+ ```
873
+
874
+ > **注意事项**:`<inheritdoc />` 不指定 `cref` 仅限成员可用且所在的类型必须指定 `<inheritdoc cref="" />`,这样才能自动识别。
875
+
876
+ ### 6.5.32 启用 All Groups 分组功能
877
+
878
+ > **版本说明**:仅限 Furion v3.3.4+ 版本使用。
879
+
880
+ ```json
881
+ {
882
+ "SpecificationDocumentSettings": {
883
+ "EnableAllGroups": true
884
+ }
885
+ }
886
+ ```
887
+
888
+ ### 6.5.33 接口过时控制
889
+
890
+ > **版本说明**:仅限 Furion v3.3.5+ 版本使用。
891
+
892
+ 只需要在方法上面贴 `[Obsolete]` 即可:
893
+
894
+ ```csharp
895
+ [Obsolete("GetName() 已经过时,请调用 GetFrameworkName() 替代")]
896
+ public string GetName()
897
+ {
898
+ return nameof(Furion);
899
+ }
900
+ ```
901
+
902
+ ### 6.5.34 单一接口更多描述
903
+
904
+ > **版本说明**:仅限 Furion v3.3.5+ 版本使用。
905
+
906
+ ```csharp
907
+ [ApiDescriptionSettings(Description = "我是一段描述,显示更多内容 <button>我是按钮</button>")]
908
+ public string add()
909
+ {
910
+ //....
911
+ }
912
+ ```
913
+
914
+ ### 6.5.35 Swagger 异常/不能显示/错误处理
915
+
916
+ 有时候可能因为错误的配置导致 Swagger 不能显示,这时候只需要复制提示的错误 `.json` 链接地址到浏览器中访问即可:
917
+
918
+ ```
919
+ https://localhost:你的端口/swagger/Default/swagger.json
920
+ ```
921
+
922
+ 这样就可以看到详细的错误了。
923
+
924
+ ### 6.5.36 自定义 Swagger 的 SchemaId
925
+
926
+ > **版本说明**:仅限 Furion v3.6.4+ 版本使用。
927
+
928
+ ```csharp
929
+ using Furion.SpecificationDocument;
930
+
931
+ [SchemaId("Other_")]
932
+ public class PersonDto
933
+ {
934
+ // ...
935
+ }
936
+ ```
937
+
938
+ `SchemaIdAttribute` 配置选项:
939
+
940
+ | 属性 | 类型 | 说明 |
941
+ |------|------|------|
942
+ | `SchemaId` | string | 自定义 SchemaId,只能是字母、数字、下划线组合 |
943
+ | `Replace` | bool | 是否完全替换,默认 false(默认是作为前缀拼接) |
944
+
945
+ ### 6.5.37 自定义 Swagger 的 OperationId
946
+
947
+ > **版本说明**:仅限 Furion 4.1.7+ 版本使用。
948
+
949
+ ```csharp
950
+ using Furion.SpecificationDocument;
951
+
952
+ public class PersonDto
953
+ {
954
+ [OperationId("MyClientMethodName")]
955
+ public string TestMethod()
956
+ {
957
+ // ...
958
+ }
959
+ }
960
+ ```
961
+
962
+ ### 6.5.38 Swagger 接口文档支持完整的 Markdown
963
+
964
+ 在 Furion 最新版中,支持了完整的 Markdown 注释,通过 `/// <remarks>` 标签编写 Markdown 内容即可在 Swagger 中渲染。
965
+
966
+ ### 6.5.39 第三方 UI 集成,如 Knife4jUI
967
+
968
+ 在 `YourPoject.Web.Core` 层安装 `IGeekFan.AspNetCore.Knife4jUI` 即可。
969
+
970
+ **Knife4jUI 独立版本配置:**
971
+
972
+ ```csharp
973
+ var routePrefix = "api";
974
+
975
+ app.UseKnife4UI(options =>
976
+ {
977
+ options.RoutePrefix = routePrefix;
978
+ foreach (var groupInfo in SpecificationDocumentBuilder.GetOpenApiGroups())
979
+ {
980
+ options.SwaggerEndpoint("/" + groupInfo.RouteTemplate, groupInfo.Title);
981
+ }
982
+ });
983
+
984
+ app.UseInject(routePrefix);
985
+ ```
986
+
987
+ **Knife4jUI 和 Swagger 共存版本配置:**
988
+
989
+ ```csharp
990
+ app.UseKnife4UI(options =>
991
+ {
992
+ options.RoutePrefix = "newapi";
993
+ foreach (var groupInfo in SpecificationDocumentBuilder.GetOpenApiGroups())
994
+ {
995
+ options.SwaggerEndpoint("/" + groupInfo.RouteTemplate, groupInfo.Title);
996
+ }
997
+ });
998
+
999
+ app.UseInject(); // Furion 默认 api 地址为 /api
1000
+ ```
1001
+
1002
+ 如需实现登录之后自动将 token 添加到头部可在登录接口 `AfterScript` 执行:
1003
+
1004
+ ```javascript
1005
+ ke.global.setAllHeader(
1006
+ "Authorization",
1007
+ "Bearer " + ke.response.headers["access-token"],
1008
+ );
1009
+ ```
1010
+
1011
+ ### 6.5.40 添加 Swagger 请求响应拦截
1012
+
1013
+ ```csharp
1014
+ app.UseInject(options =>
1015
+ {
1016
+ options.ConfigureSwaggerUI(ui =>
1017
+ {
1018
+ // 请求拦截
1019
+ ui.UseRequestInterceptor("function(request) { return defaultRequestInterceptor(request); }");
1020
+ // 响应拦截
1021
+ ui.UseResponseInterceptor("function(response) { return defaultResponseInterceptor(response); }");
1022
+ });
1023
+ });
1024
+ ```
1025
+
1026
+ > **注意**:`UseRequestInterceptor` 和 `UseResponseInterceptor` 代码**不能换行**且须在 `defaultRequestInterceptor(request)` 和 `defaultResponseInterceptor(response)` 之前编写自定义代码。
1027
+
1028
+ 添加自定义 header 示例:
1029
+
1030
+ ```csharp
1031
+ app.UseInject(options =>
1032
+ {
1033
+ options.ConfigureSwaggerUI(ui =>
1034
+ {
1035
+ // 注意代码不能换行!
1036
+ ui.UseRequestInterceptor("function(request) { request.headers['framework']='Furion'; return defaultRequestInterceptor(request); }");
1037
+ });
1038
+ });
1039
+ ```
1040
+
1041
+ ### 6.5.41 枚举类型值
1042
+
1043
+ > **版本说明**:仅限 Furion 4.8.8.35+ 版本使用。
1044
+
1045
+ 默认情况下枚举类型值会生成字符串类型,如需生成值类型则添加 `[EnumToNumber]` 特性。如果枚举项存在中文,会强制生成为值类型。
1046
+
1047
+ ```csharp
1048
+ [EnumToNumber]
1049
+ public enum NoticeTypeEnum
1050
+ {
1051
+ NOTICE = 1,
1052
+ ANNOUNCEMENT = 2,
1053
+ }
1054
+ ```
1055
+
1056
+ 也支持全局配置:
1057
+
1058
+ ```json
1059
+ {
1060
+ "SpecificationDocumentSettings": {
1061
+ "EnumToNumber": true
1062
+ }
1063
+ }
1064
+ ```
1065
+
1066
+ ### 6.5.42 运行时修改 Swagger UI 信息
1067
+
1068
+ 通过依赖注入 `ISwaggerProvider` 接口操作:
1069
+
1070
+ ```csharp
1071
+ var openApiInfos = SpecificationDocumentBuilder.GetOpenApiGroups();
1072
+ var openApiDocument = _swaggerProvider.GetSwagger("Default");
1073
+
1074
+ openApiDocument.Info.Title = "我是新标题";
1075
+ openApiDocument.Info.Description = "我是新描述";
1076
+ ```
1077
+
1078
+ ### 6.5.43 隐藏特定控制器或 Action
1079
+
1080
+ ```csharp
1081
+ [ApiDescriptionSettings(false)]
1082
+ public void IgnoreSomeMethod()
1083
+ {
1084
+ }
1085
+
1086
+ // Furion 4.9.3.1+ 支持
1087
+ [SwaggerIgnore] // 支持类、方法、函数、参数、属性
1088
+ public void IgnoreSomeMethod()
1089
+ {
1090
+ }
1091
+ ```
1092
+
1093
+ > 如果不希望生成路由,那么可贴 `[NonAction]` 特性或者选择非 `public` 修饰即可。
1094
+
1095
+ ### 6.5.44 二级虚拟目录/Yarp/Nginx 代理问题
1096
+
1097
+ > **版本说明**:仅限 Furion 4.9.3.1+ 版本使用。
1098
+
1099
+ ```csharp
1100
+ // 多种配置方式,取其一即可
1101
+ app.UseInject(withProxy: true);
1102
+ app.UseInject(string.Empty, withProxy: true);
1103
+ app.UseInject("api", withProxy: true);
1104
+ app.UseInject("api/abc", withProxy: true);
1105
+ ```
1106
+
1107
+ ### 6.5.45 控制 Schema 展开深度
1108
+
1109
+ ```csharp
1110
+ app.UseInject(options =>
1111
+ {
1112
+ options.ConfigureSwaggerUI(ui =>
1113
+ {
1114
+ ui.DefaultModelExpandDepth(5);
1115
+ });
1116
+ });
1117
+ ```
1118
+
1119
+ ### 6.5.46 第三方 UI 集成,如 Scalar
1120
+
1121
+ 在 `YourPoject.Web.Core` 层安装 `Scalar.AspNetCore` 即可。
1122
+
1123
+ ```csharp
1124
+ app.UseInject();
1125
+
1126
+ app.UseEndpoints(endpoints =>
1127
+ {
1128
+ endpoints.MapScalarApiReference(options =>
1129
+ {
1130
+ foreach (var groupInfo in SpecificationDocumentBuilder.GetOpenApiGroups())
1131
+ {
1132
+ options.AddDocument(groupInfo.Group, groupInfo.Title, groupInfo.RouteTemplate);
1133
+ }
1134
+ });
1135
+ });
1136
+ ```
1137
+
1138
+ 之后打开浏览器访问 `/scalar` 即可。
1139
+
1140
+ 还可以通过 `HttpContext` 判断实现授权登录:
1141
+
1142
+ ```csharp
1143
+ endpoints.MapScalarApiReference("myapi", (options, httpContext) =>
1144
+ {
1145
+ foreach (var groupInfo in SpecificationDocumentBuilder.GetOpenApiGroups())
1146
+ {
1147
+ options.AddDocument(groupInfo.Group, groupInfo.Title, groupInfo.RouteTemplate);
1148
+ }
1149
+ });
1150
+ ```
1151
+
1152
+ ---
1153
+
1154
+ ## 6.6 SpecificationDocumentSettings 配置
1155
+
1156
+ | 配置项 | 类型 | 默认值 | 说明 |
1157
+ |--------|------|--------|------|
1158
+ | `DocumentTitle` | string | `Specification Api Document` | 文档标题 |
1159
+ | `DefaultGroupName` | string | `Default` | 默认分组名 |
1160
+ | `EnableAuthorized` | bool | `true` | 是否启用权限控制 |
1161
+ | `LatestVersion` | bool | `false` | 采用最新 Swagger 版本(4.9.7.205+) |
1162
+ | `RoutePrefix` | string | `api` | 规范化文档地址,设空字符串则为首页 |
1163
+ | `DocExpansionState` | DocExpansion | `List` | 文档显示方式:List / Full / None |
1164
+ | `XmlComments` | string | 三个默认程序集 | 程序集注释描述文件名 |
1165
+ | `GroupOpenApiInfos` | SpecificationOpenApiInfo[] | `{ 'Group': 'Default'}` | 分组信息配置 |
1166
+ | `SecurityDefinitions` | SpecificationOpenApiSecurityScheme[] | `[]` | 安全策略定义配置 |
1167
+ | `Servers` | OpenApiServer[] | `[]` | 配置 Server 下拉列表 |
1168
+ | `HideServers` | bool | `true` | 是否隐藏 Server 下拉列表 |
1169
+ | `RouteTemplate` | string | `swagger/{documentName}/swagger.json` | 文档路由模板 |
1170
+ | `PackagesGroups` | string[] | `[]` | 模块化内置分组名称 |
1171
+ | `EnableEnumSchemaFilter` | bool | `true` | 启用枚举 Schema 筛选器 |
1172
+ | `EnableTagsOrderDocumentFilter` | bool | `true` | 启用标签排序筛选器 |
1173
+ | `ServerDir` | string | 空 | IIS Application 部署名(v3.2.0+) |
1174
+ | `LoginInfo` | SpecificationLoginInfo | `null` | 登录配置(v3.3.3+) |
1175
+ | `EnableAllGroups` | bool | `false` | 启用总分组功能(v3.3.4+) |
1176
+ | `EnumToNumber` | bool | `false` | 枚举生成值类型(4.8.8.35+) |
1177
+ | `EnableXmlComments` | bool | `true` | 是否自动加载 Xml 注释(4.9.3.1+) |
1178
+
1179
+ `SpecificationOpenApiInfo` 内置配置:
1180
+
1181
+ | 属性 | 类型 | 说明 |
1182
+ |------|------|------|
1183
+ | `Group` | string | 分组唯一标识,必填 |
1184
+ | `Order` | int | 分组排序,数字越大排前面,默认 0 |
1185
+ | `Visible` | bool | 配置分组是否可见,默认 true |
1186
+ | `Title` | string | 配置分组标题 |
1187
+ | `Description` | string | 配置分组描述 |
1188
+ | `Version` | string | 配置分组版本,默认 1.0 |
1189
+ | `TermsOfService` | Uri | 配置相关链接地址 |
1190
+ | `Contact` | OpenApiContact | 配置联系方式 |
1191
+ | `License` | OpenApiLicense | 配置协议 |
1192
+
1193
+ ---
1194
+
1195
+ ## 6.7 统一返回值模型/规范化结果/API 返回值
1196
+
1197
+ Furion 框架提供规范化结果功能,可以通过实现 `IUnifyResultProvider` 提供器实现统一规范化返回值定制。
1198
+
1199
+ ### 定义结果包装类型
1200
+
1201
+ ```csharp
1202
+ // 必须是泛型类型
1203
+ public class YourRESTfulResult<T>
1204
+ {
1205
+ /// <summary>
1206
+ /// 状态码
1207
+ /// </summary>
1208
+ public int? StatusCode { get; set; }
1209
+
1210
+ /// <summary>
1211
+ /// 数据
1212
+ /// </summary>
1213
+ public T Data { get; set; }
1214
+
1215
+ /// <summary>
1216
+ /// 执行成功
1217
+ /// </summary>
1218
+ public bool Succeeded { get; set; }
1219
+
1220
+ /// <summary>
1221
+ /// 错误信息
1222
+ /// </summary>
1223
+ public object Errors { get; set; }
1224
+
1225
+ /// <summary>
1226
+ /// 附加数据
1227
+ /// </summary>
1228
+ public object Extras { get; set; }
1229
+
1230
+ /// <summary>
1231
+ /// 时间戳
1232
+ /// </summary>
1233
+ public long Timestamp { get; set; }
1234
+ }
1235
+ ```
1236
+
1237
+ ### 定义 IUnifyResultProvider 实现类
1238
+
1239
+ 贴特性 `[UnifyModel(typeof(YourRESTfulResult<>))]`:
1240
+
1241
+ ```csharp
1242
+ using Furion.DataValidation;
1243
+ using Furion.UnifyResult.Internal;
1244
+ using Microsoft.AspNetCore.Http;
1245
+ using Microsoft.AspNetCore.Mvc;
1246
+ using Microsoft.AspNetCore.Mvc.Filters;
1247
+ using System;
1248
+ using System.Threading.Tasks;
1249
+
1250
+ namespace YourProject.UnifyResult
1251
+ {
1252
+ [UnifyModel(typeof(YourRESTfulResult<>))]
1253
+ public class YourRESTfulResultProvider : IUnifyResultProvider
1254
+ {
1255
+ public IActionResult OnAuthorizeException(DefaultHttpContext context, ExceptionMetadata metadata)
1256
+ {
1257
+ return new JsonResult(YourRESTfulResult(metadata.StatusCode, data: metadata.Data, errors: metadata.Errors)
1258
+ , UnifyContext.GetSerializerSettings(context));
1259
+ }
1260
+
1261
+ public IActionResult OnException(ExceptionContext context, ExceptionMetadata metadata)
1262
+ {
1263
+ return new JsonResult(YourRESTfulResult(metadata.StatusCode, data: metadata.Data, errors: metadata.Errors)
1264
+ , UnifyContext.GetSerializerSettings(context));
1265
+ }
1266
+
1267
+ public IActionResult OnSucceeded(ActionExecutedContext context, object data)
1268
+ {
1269
+ return new JsonResult(YourRESTfulResult(StatusCodes.Status200OK, true, data)
1270
+ , UnifyContext.GetSerializerSettings(context));
1271
+ }
1272
+
1273
+ public IActionResult OnValidateFailed(ActionExecutingContext context, ValidationMetadata metadata)
1274
+ {
1275
+ return new JsonResult(YourRESTfulResult(metadata.StatusCode ?? StatusCodes.Status400BadRequest, data: metadata.Data, errors: metadata.ValidationResult)
1276
+ , UnifyContext.GetSerializerSettings(context));
1277
+ }
1278
+
1279
+ public async Task OnResponseStatusCodes(HttpContext context, int statusCode, UnifyResultSettingsOptions unifyResultSettings)
1280
+ {
1281
+ UnifyContext.SetResponseStatusCodes(context, statusCode, unifyResultSettings);
1282
+
1283
+ switch (statusCode)
1284
+ {
1285
+ case StatusCodes.Status401Unauthorized:
1286
+ await context.Response.WriteAsJsonAsync(YourRESTfulResult(statusCode, errors: "401 Unauthorized")
1287
+ , App.GetOptions<JsonOptions>()?.JsonSerializerOptions);
1288
+ break;
1289
+ case StatusCodes.Status403Forbidden:
1290
+ await context.Response.WriteAsJsonAsync(YourRESTfulResult(statusCode, errors: "403 Forbidden")
1291
+ , App.GetOptions<JsonOptions>()?.JsonSerializerOptions);
1292
+ break;
1293
+ default: break;
1294
+ }
1295
+ }
1296
+
1297
+ private static YourRESTfulResult<object> YourRESTfulResult(int statusCode, bool succeeded = default, object data = default, object errors = default)
1298
+ {
1299
+ return new YourRESTfulResult<object>
1300
+ {
1301
+ StatusCode = statusCode,
1302
+ Succeeded = succeeded,
1303
+ Data = data,
1304
+ Errors = errors,
1305
+ Extras = UnifyContext.Take(),
1306
+ Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
1307
+ };
1308
+ }
1309
+ }
1310
+ }
1311
+ ```
1312
+
1313
+ ### 注册
1314
+
1315
+ ```csharp
1316
+ services.AddControllers()
1317
+ .AddInjectWithUnifyResult<YourRESTfulResultProvider>();
1318
+ ```
1319
+
1320
+ > **特别注意**:默认情况下,规范化结果不会对 401、403、404 状态码进行规范化处理,如需启用:
1321
+
1322
+ ```csharp
1323
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
1324
+ {
1325
+ // 添加规范化结果状态码,需要在这里注册
1326
+ app.UseUnifyResultStatusCodes();
1327
+ // 如果和域登录冲突可设置参数 withAuthorizationHeaderCheck: false
1328
+ }
1329
+ ```
1330
+
1331
+ ### 6.7.1 排除规范化处理
1332
+
1333
+ 贴 `[NonUnify]` 特性即可。
1334
+
1335
+ 如果接口没有返回值(`void`/`Task`),也会被排除规范化处理。如果希望此类接口支持规范化处理,可在方法或所在的类型上添加 `[ForceUnify]` 特性。
1336
+
1337
+ ### 6.7.2 规范化结果添加额外数据
1338
+
1339
+ ```csharp
1340
+ UnifyContext.Fill(new { Message = "操作成功" });
1341
+ ```
1342
+
1343
+ ### 6.7.3 自定义特别接口规范化结果
1344
+
1345
+ ```csharp
1346
+ [UnifyResult(typeof(Person))]
1347
+ public Person GetPerson(int id)
1348
+ {
1349
+ // ...
1350
+ }
1351
+ ```
1352
+
1353
+ ---
1354
+
1355
+ ## 6.8 支持多套规范化配置
1356
+
1357
+ > **版本说明**:仅限 Furion 4.4.4+ 版本使用。
1358
+
1359
+ ### 定义规范化处理提供程序
1360
+
1361
+ ```csharp
1362
+ [UnifyModel(typeof(MyResult<>))]
1363
+ public class SpeciallyResultProvider : IUnifyResultProvider
1364
+ {
1365
+ // 参考 6.7 节的规范化处理写法实现各方法
1366
+ }
1367
+
1368
+ public class MyResult<T>
1369
+ {
1370
+ public T Data { get; set; }
1371
+ }
1372
+ ```
1373
+
1374
+ ### 注册
1375
+
1376
+ ```csharp
1377
+ services.AddUnifyProvider<SpeciallyResultProvider>("specially");
1378
+ // 指定规范化唯一名称,如果不指定就会替代默认的
1379
+ ```
1380
+
1381
+ ### 在控制器/动态 WebAPI 中使用
1382
+
1383
+ ```csharp
1384
+ public class TestUnifyProvider : IDynamicApiController
1385
+ {
1386
+ public string DefaultUnify()
1387
+ {
1388
+ return "test";
1389
+ }
1390
+
1391
+ [UnifyProvider]
1392
+ public string DefaultUnify2()
1393
+ {
1394
+ return "test";
1395
+ }
1396
+
1397
+ [UnifyProvider("specially")]
1398
+ public string SpeciallyUnify()
1399
+ {
1400
+ return "特别";
1401
+ }
1402
+ }
1403
+ ```
1404
+
1405
+ ---
1406
+
1407
+ ## 6.9 针对特定控制器或特定方法配置序列化选项
1408
+
1409
+ ### 6.9.1 通过 JsonResult 设置第二个参数
1410
+
1411
+ ```csharp
1412
+ [NonUnify]
1413
+ public IActionResult SpecialApi()
1414
+ {
1415
+ return new JsonResult(new YourRESTfulResult<object>
1416
+ {
1417
+ StatusCode = 200,
1418
+ Succeeded = true,
1419
+ Data = new { Name = "Furion" },
1420
+ Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
1421
+ }, new JsonSerializerOptions
1422
+ {
1423
+ PropertyNamingPolicy = null
1424
+ });
1425
+ }
1426
+ ```
1427
+
1428
+ ### 6.9.2 注册多套序列化配置选项(推荐)
1429
+
1430
+ > **版本说明**:仅限 Furion 4.6.6+ 版本使用。
1431
+
1432
+ ```csharp
1433
+ services.AddUnifyJsonOptions("special", new JsonSerializerOptions
1434
+ {
1435
+ PropertyNamingPolicy = null
1436
+ });
1437
+ ```
1438
+
1439
+ 使用方式:
1440
+
1441
+ ```csharp
1442
+ [UnifySerializerSetting("special")]
1443
+ public object SpecialApi()
1444
+ {
1445
+ return new { Name = "Furion" };
1446
+ }
1447
+ ```
1448
+
1449
+ 也可以手动返回 `IActionResult`(Furion 4.8.7.1+):
1450
+
1451
+ ```csharp
1452
+ public IActionResult SpecialApi()
1453
+ {
1454
+ return new JsonResult(new { Name = "Furion" }, UnifyContext.GetSerializerSettings("special"));
1455
+ }
1456
+ ```
1457
+
1458
+ > **特别提醒**:目前 Swagger 暂未提供个别的接口自定义 schema 序列化选项。