6. 规范化接口文档
6.1 什么是接口文档
在现在移动为王、多端互辅、前端百花齐放的开放时代,不再是一人包揽式开发,大家各司其职,后端工程师负责接口开发,前端负责接口联调,也就是互联网现在流行的前后端分离架构。
所以就需要由前后端工程师共同定义接口,编写接口文档,之后大家按照这个接口文档进行开发、维护及开放给第三方。
6.2 为什么要写接口文档
- 能够让前端开发与后台开发人员更好的配合,提高工作效率
- 项目迭代或者项目人员更迭时,方便后期人员查看和维护
- 方便测试人员进行接口测试
6.3 为什么需要规范化文档
由于每个公司后端人员技术参差不齐,技术文档能力也不例外,导致接口定义及文档五花八门,不同项目或不同公司对接极其困难,而且体验糟糕。所以,无规矩不成方圆,为了开发人员间更好的配合,迫切需要整理出一套规范。
通常接口规范分为六个部分:
6.3.1 协议规范
为了确保不同系统/模块间的数据交互,需要事先约定好通讯协议,如:TCP、HTTP、HTTPS 协议。为了确保数据交互安全,建议使用 HTTPS 协议
6.3.2 接口路径规范
作为接口路径,为了方便清晰的区分来自不同的系统,可以采用不同系统/模块名作为接口路径前缀,如:支付模块:/pay/xxx
,订单模块:/order/xxx
6.3.3 版本控制规范
为了便于后期接口的升级和维护,建议在接口路径中加入版本号,便于管理,实现接口多版本的可维护性。如:接口路径中添加类似"v1
"、"v2
"等版本号
6.3.4 接口命名规范
和 C# 命名规范一样,好的、统一的接口命名规范,不仅可以增强其可读性,而且还会减少很多不必要的口头/书面上的解释。可使用"驼峰命名法"按照实现接口的业务类型、业务场景等命名,有必要时可采取多级目录命名,但目录不宜过长,两级目录较为适宜
常见命名方式
:接口名称动词前/后缀化
: 接口名称以接口数据操作的动词为前/后缀,常见动词有:Add、Delete、Update、Query、Get、Send、Save、Detail、List
等,如:新建用户AddUser
、查询订单详情QueryOrderDetail
。接口名称动词 + 请求方式
:接口路径中包含具体接口名称的名词,接口数据操作动作以 HTTP 请求方式来区分。常用的 HTTP 请求方式有:GET
:从服务器取出资源(一项或多项)POST
:在服务器新建一个资源PUT
:在服务器更新资源(客户端提供改变后的完整资源)PATCH
:在服务器更新资源(客户端提供改变的属性)DELETE
:从服务器删除资源
6.3.5 请求参数规范
请求方式
:按照GET、POST、PUT
等含义定义,避免出现不一致现象,对人造成误解、歧义请求头
:请求头根据项目需求添加配置参数。如:请求数据格式,accept=application/json
等。如有需要,请求头可根据项目需求要求传入用户 token、唯一验签码等加密数据请求参数/请求体
: 请求参数字段,尽可能与数据库表字段、对象属性名等保持一致,因为保持一致是最省事,最舒服的一件事
6.3.6 返回数据规范
统一规范返回数据的格式,对己对彼都有好处,此处以 json 格式为例。返回数据应包含:返回状态码、返回状态信息、具体数据。返回数据中的状态码、状态信息,常指具体的业务状态,不建议和 HTTP 状态码混在一起。HTTP 状态,是用来体现 HTTP 链路状态情况,如:404-Not Found。HTTP 状态码和 json 结果中的状态码,并存尚可,用于体现不同维度的状态。
6.4 什么是 Swagger
相信无论是前端还是后端开发,都或多或少地被接口文档折磨过。前端经常抱怨后端给的接口文档与实际情况不一致。后端又觉得编写及维护接口文档会耗费不少精力,经常来不及更新。
其实无论是前端调用后端,还是后端调用后端,都期望有一个好的接口文档。但是这个接口文档对于程序员来说,就跟注释一样,经常会抱怨别人写的代码没有写注释,然而自己写起代码起来,最讨厌的,也是写注释。所以仅仅只通过强制来规范大家是不够的,随着时间推移,版本迭代,接口文档往往很容易就跟不上代码了。
发现了痛点就要去找解决方案。解决方案用的人多了,就成了标准的规范,这就是 Swagger
的由来。
通过这套规范,你只需要按照它的规范去定义接口及接口相关的信息。再通过 Swagger
衍生出来的一系列项目和工具,就可以做到生成各种格式的接口文档,生成多种语言的客户端和服务端的代码,以及在线接口调试页面等等。
这样,如果按照新的开发模式,在开发新版本或者迭代版本的时候,只需要更新 Swagger
描述文件,就可以自动生成接口文档和客户端服务端代码,做到调用端代码、服务端代码以及接口文档的一致性。
所以,Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化RESTful
风格的 Web
服务。
总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法、参数和模型紧密集成到服务器端的代码,允许 API 来始终保持同步。Swagger
让部署管理和使用功能强大的 API
从未如此简单。
6.5 Swagger 使用
Furion
框架提供了非常方便且灵活的 Swagger
配置,无需增加额外学习成本。
6.5.1 注册服务
.UseInject()
已经包含了 .UseSpecificationDocuments()
注册,无需再次注册。
using Microsoft.AspNetCore.Builder;using Microsoft.AspNetCore.Hosting;using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Hosting;namespace Furion.Web.Core{ [AppStartup(800)] public sealed class FurWebCoreStartup : AppStartup { public void ConfigureServices(IServiceCollection services) { services.AddSpecificationDocuments(); services.AddControllers(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // Other Codes app.UseSpecificationDocuments(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } }}
services.AddSpecificationDocuments()
通常和 .AddDynamicApiControllers()
成对出现。
6.5.2 默认地址
在 Furion
框架中,默认 规范化文档
地址为 /api
目录,支持自定义配置。
如下图所示:

可以通过两种方式配置:
app.UseInject("路由")
方式,如
app.UseInject("testapi"); // 那么 /testapi 就是规范化地址
配置文件配置
:
{ "SpecificationDocumentSettings": { "RoutePrefix": "testapi" }}
配置文件优先级大于 UseInject()
方式
6.5.3 默认分组
Furion
框架中默认分组名为 Default
,支持自定义配置。
{ "SpecificationDocumentSettings": { "DefaultGroupName": "MyGroup" }}
6.5.4 文档注释
规范化文档默认扫描 Furion.Application
,Furion.Web.Core
,Furion.Web.Entry
三个程序集.xml
注释文件,支持自定义配置。
只支持 ///
标识的注释语法,如:类、方法、属性、参数、返回值、验证特性。
using Furion.DynamicApiController;namespace Furion.Application{ /// <summary> /// 类注释 /// </summary> public class FurionAppService : IDynamicApiController { /// <summary> /// 方法注释 /// </summary> /// <returns></returns> public string Get() { return nameof(Furion); } /// <summary> /// 带 ID 参数的方法注释 /// </summary> /// <param name="id"></param> /// <returns></returns> public int Get(int id) { return id; } }}
如下图所示:

如果文档注释没有显示,请检查项目 属性->生成->输出
中 XML 文档是否配置输出路径。注意:只有不带路径的 【项目名称.xml】 才会自动加载。
Debug
模式下和 Release
模式下的注释文件是不通用的,所以导致很多开发者发布到服务器上发现没有显示注释。我们只需要在 Visual Studio
中切换 Debug
模式为 Release
,然后重新配置一次即可。
这样不管是 Debug
还是 Release
模式都会显示注释了。
6.5.5 多分组支持
多分组是一个系统中必备功能,我们可以将系统划分为多个模块,每个模块都独立的 api
配置。在 Furion
框架中,实现多分组非常简单。如:
using Furion.DynamicApiController;namespace Furion.Application{ [ApiDescriptionSettings("Group1")] public class FurionAppService : IDynamicApiController { /// <summary> /// 随父类 Group1 分组 /// </summary> /// <returns></returns> public string Post() { return nameof(Furion); } /// <summary> /// 在 Group1、Group3 都有我 /// </summary> /// <returns></returns> [ApiDescriptionSettings("Group1", "Group3")] public string Get() { return nameof(Furion); } /// <summary> /// 我只在 Group2 出现 /// </summary> /// <param name="id"></param> /// <returns></returns> [ApiDescriptionSettings("Group2")] public int Get(int id) { return id; } }}
如下图所示:

6.5.6 多分组排序
- 方式一
- 方式二
通过分组名称添加 @整数
进行排序
using Furion.DynamicApiController;namespace Furion.Application{ [ApiDescriptionSettings("Group1@1")] public class FurionAppService : IDynamicApiController { public string Post() { return nameof(Furion); } [ApiDescriptionSettings("Group1", "Group3")] public string Get() { return nameof(Furion); } [ApiDescriptionSettings("Group@2")] public int Get(int id) { return id; } }}
可以通过在分组名后面添加 @整数
进行排序,整数
越大排前面。如果分组名称多次指定且多次指定了 @整数
,则自动取该分组最大的整数进行排序。
通过配置文件配置排序
{ "SpecificationDocumentSettings": { "GroupOpenApiInfos": [ { "Group": "Group1", "Order": 1 }, { "Group": "Group2", "Order": 2 }, { "Group": "Group3", "Order": 0 } ] }}
如下图所示:

分组默认排序 Order
为 0
。如果同时配置了 @整数
和 appsettings.json
配置文件,那么优先采用 appsettings.json
中的 Order
6.5.7 多分组信息配置
Furion
框架提供了可通过 appsetting.json
配置分组信息:
{ "SpecificationDocumentSettings": { "GroupOpenApiInfos": [ { "Group": "Group1", "Title": "分组标题", "Description": "这里是分组描述", "Version": "版本号", "TermsOfService": "https://furion.icu", "Contact": { "Name": "百小僧", "Url": "https://gitee.com/monksoul", "Email": "monksoul@outlook.com" }, "License": { "Name": "MIT", "Url": "https://gitee.com/dotnetchina/Furion/blob/alpha/LICENSE" } } ] }}
如下图所示:

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

using Furion.DynamicApiController;namespace Furion.Application{ [ApiDescriptionSettings(Tag = "合并所有标签")] public class FurionAppService : IDynamicApiController { public string Get() { return nameof(Furion); } public int Get(int id) { return id; } } [ApiDescriptionSettings(Tag = "合并所有标签")] public class TestAppService : IDynamicApiController { public string Get() { return nameof(Furion); } public int Get(int id) { return id; } }}
如下图所示:

如果 Tag
名字一样,则会自动合并,否则只是命名。
6.5.9 默认展开所有文档
{ "SpecificationDocumentSettings": { "DocExpansionState": "Full" }}
如下图所示:

DocExpansionState
配置说明:
List
:列表式(展开子类),默认值Full
:完全展开None
:列表式(不展开子类)
6.5.10 配置文档标题
{ "SpecificationDocumentSettings": { "DocumentTitle": "我是自定义标题" }}
如下图所示:

6.5.11 授权控制
新版本 Furion
已经默认启用了 Bearer Token 授权配置,无需手动配置,如需手动配置,可手动添加以下类似配置:
{ "SpecificationDocumentSettings": { "EnableAuthorized": true, "SecurityDefinitions": [ { "Id": "Bearer", "Type": "Http", "Name": "Authorization", "Description": "JWT Authorization header using the Bearer scheme.", "BearerFormat": "JWT", "Scheme": "bearer", "In": "Header", "Requirement": { "Scheme": { "Reference": { "Id": "Bearer", "Type": "SecurityScheme" }, "Accesses": [] } } } ] }}
6.5.12 在线测试
如下图所示:

6.5.13 性能监视 MiniProfiler
规范化文档默认集成了 MiniProfiler
第三方性能组件,通过该组件可以方便查看请求性能、异常堆栈、数据库操作等信息。默认在 Swagger
首页左上角显示。
如下图所示:

也可以通过 appsetting.json
中 AppSettings:InjectMiniProfiler
设为 false
关闭。
6.5.14 定义接口输出类型
using Furion.DynamicApiController;using Microsoft.AspNetCore.Mvc;namespace Furion.Application{ public class FurionAppService : IDynamicApiController { [ProducesResponseType(201, Type = typeof(TestDto))] [ProducesResponseType(400)] public string Get() { return nameof(Furion); } }}
如下图所示:

6.5.15 隐藏特定分组
Furion
新版本提供了隐藏分组的 Visible
配置,设置为 false
之后该分组将不显示在规范化文档中,如:
{ "SpecificationDocumentSettings": { "GroupOpenApiInfos": [ { "Group": "Group1", "Visible": false } ] }}
6.5.16 中文乱码问题
默认情况下,.json
文件并未采用 utf-8
编码,所以如果配置中文分组信息就会出现乱码情况,这时候,只需要修改 .json
文件编码为 utf-8
即可。
6.5.17 生产环境中关闭 Swagger
如果不需要线上环境开启 Swagger
功能,只需要在 appsetting.json
配置即可:
{ "AppSettings": { "InjectSpecificationDocument": false }}
6.5.18 设置 Example Value
默认值
Swagger
会自动根据对象类型输入参数添加 Example Value
默认值,但是该默认值通常是对象属性的类型字符串或缺省值,如果我们需要自定义这些默认值,只需要添加 /// <example>默认值</example>
注释即可。
如:
/// <summary>/// 年龄/// </summary>/// <example>13</example>[Required, Range(10, 110)]public int Age { get; set; }
如下图所示:

更多类型默认值设置示例:
bool
类型:/// <example>true</example>
string
类型:/// <example>foobar</example>
number
类型:/// <example>123</example>
null
类型:/// <example>null</example>
array
类型:/// <example>[ 1, 2, 3 ]</example>
object
类型输入参数默认情况下,Example Value
不会显示 object
类型的对象属性,因为 Swagger
认为这是不合理的定义。如果需要强制显示,只需要添加 /// <example>"object"</example>
注释即可。
6.5.19 自定义 Swagger
配置
Furion
框架除了内置了不少配置以外,还提供了直接配置 Swagger
Api 的参数,如:
public void ConfigureServices(IServiceCollection services){ services.AddInject(options => { options.SpecificationDocumentConfigure = spt => { spt.SwaggerGenConfigure = gen => { // 配置 Swagger Gen }; }; });}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseInject(configure: options => { options.SpecificationDocumentConfigure = spt => { spt.SwaggerConfigure = swg => { // 配置 Swagger Options }; spt.SwaggerUIConfigure = ui => { // 配置 Swagger UI }; }; });}
6.5.20 配置 Swagger
的 Schemes
Furion
框架默认只显示名称,如果需要自定义显示规则,只需要添加配置即可。
services.AddControllersWithViews() .AddInject(options => { options.SpecificationDocumentConfigure = spt => { spt.SwaggerGenConfigure = gen => { gen.CustomSchemaIds(x => x.FullName); }; }; });
6.5.21 自定义 swagger.json
路由模板
默认情况下,Furion
框架会生成统一的分组模板,如:swagger/{documentName}/swagger.json
,{documentName}
会在运行时替换为分组名,如需自定义,配置 RouteTemplate
即可:
{ "SpecificationDocumentSettings": { "RouteTemplate": "myapp/{documentName}/xxxx.json" }}
6.5.22 关于 application/x-www-form-urlencoded
请求
默认情况下,Swagger
并未添加 application/x-www-form-urlencoded
支持,如需启用该配置,只需在方法顶部贴 [Consumes]
特性即可,如:
[Consumes("application/x-www-form-urlencoded")]public async Task<IActionResult> Test([FromForm] TestRequest testRequest){ // ....}public class TestRequest{ public string TestValue { get; set; }}
参数必须贴 [FromForm]
特性。另外请求时将参数按 URL
地址拼接并放在 Body
中请求。
6.5.23 Swagger
出现 CORS
问题解决
如果 Swagger
出现以下错误,如图:

则需要添加以下配置:
{ "SpecificationDocumentSettings": { "HideServers": true }}
6.5.24 Swagger
出现默认 xml
参数问题解决
产生此原因有两个必要条件:
- 使用了
Microsoft.AspNetCore.Mvc.NewtonsoftJson
包并添加了AddNewtonsoftJson()
注册。 .AddNewtonsoftJson()
写在了.AddInjectWithUnifyResult()
后面。
所以解决方法是,先注册 .AddNewtonsoftJson()
再注册规范化结果,如:
services.AddControllers() .AddNewtonsoftJson() .AddInjectWithUnifyResult();
6.5.25 Swagger
多语言支持
在 Furion 2.9.0 +
版本已经支持了 Swagger
文档地址 ?culture=en-US
参数多语言转发功能了,也就是 Swagger
地址带 ?culture=
参数将自动添加到每一个请求的 api
地址中。
6.5.26 自定义逻辑控制 Swagger
每一个 api
可见性
有时候我们需要自定义 Swagger
接口可见性,比如根据权限,不同用户类型,各种逻辑控制,如:
// 也可以用 .AddInjectWithUnifyResultservices.AddInject(options => { options.SpecificationDocumentConfigure = spt => { spt.SwaggerGenConfigure = gen => { gen.DocInclusionPredicate((currentGroup, apiDescription) => { // Furion 内部检查,必须放第一行 var isShow = SpecificationDocumentBuilder.CheckApiDescriptionInCurrentGroup(currentGroup, apiDescription); // 获取当前方法 _ = apiDescription.TryGetMethodInfo(out var method); // 有了方法,这里做你想做的事情,isShow 设置 true 可见,设置 false 不可见 return isShow; }); }; }; });
6.5.27 配置 MVC
控制器支持规范化处理
{ "UnifyResultSettings": { "SupportMvcController": true }}
6.5.28 Swagger
刷新记住授权状态
默认情况下,Swagger
刷新浏览器后,授权状态将被重置,也就是需要重新登录,通过下面代码在 用户登录成功后 调用即可:
// ....验证用户名/密码...._httpContextAccessor.HttpContext.SigninToSwagger("传入 token");
6.5.29 带登录的 Swagger
文档
以下内容仅限 Furion v3.3.3+
版本使用。
默认情况下,Swagger
是任何人都可以访问的,这样也暴露出一些安全问题,所以在该版本之后添加了登录功能,只需要配置 SpecificationDocumentSettings
的 LoginInfo
即可:
{ "SpecificationDocumentSettings": { "LoginInfo": { "Enabled": true, "CheckUrl": "/Home/CheckUrl", "SubmitUrl": "/Home/SubmitUrl", "UserName": "admin", "Password": "admin" } }}
配置说明
LoginInfo
:配置Swagger
是否需要登录才能访问,SpecificationLoginInfo
类型,默认null
,仅在 Furion v3.3.3+` 有效Enabled
:是否启用登录授权,默认false
CheckUrl
:检查登录状态的Url
地址,该地址必须是POST
请求,已授权返回200
,否则返回401
,支持相对地址,以/
开头SubmitUrl
:提交登录的Url
地址,该地址必须是POST
请求且只有一个SpecificationAuth
类型参数,成功登录返回200
,否则返回401
,支持相对地址,以/
开头
配置示例
using Furion.SpecificationDocument;using Microsoft.AspNetCore.Authorization;using Microsoft.AspNetCore.Mvc;using System.ComponentModel.DataAnnotations;namespace Furion.Web.Entry.Controllers;public class HomeController : Controller{ [HttpPost, AllowAnonymous, NonUnify] public int CheckUrl() { return 401; } [HttpPost, AllowAnonymous, NonUnify] public int SubmitUrl([FromForm] SpecificationAuth auth) { // 读取配置信息 var userName = App.Configuration["SpecificationDocumentSettings:LoginInfo:UserName"]; var password = App.Configuration["SpecificationDocumentSettings:LoginInfo:Password"]; if (auth.UserName == userName && auth.Password == password) { return 200; } else { return 401; } }}

6.5.30 inheritdoc
实现注释继承
以下内容仅限 Furion v3.3.3+
版本使用。
在过去我们在接口定义的时候编写了完整的成员注释,然后在派生成员中又要重复写一次,实际上做了很大无用功,现在 Furion
支持了注释继承了,同时 Swagger
中也能正确显示。
using Furion.DynamicApiController;namespace Furion.Application{ /// <inheritdoc cref="ITestInheritdoc" /> public class TestInheritdoc : ITestInheritdoc, IDynamicApiController { /// <inheritdoc cref="ITestInheritdoc.GetName"/> public string GetName() { return "Furion"; } /// <inheritdoc /> public string GetVersion() { return "3.3.3"; } } /// <summary> /// 测试注释继承 /// </summary> public interface ITestInheritdoc { /// <summary> /// 获取名称 /// </summary> /// <returns></returns> string GetName(); /// <summary> /// 获取版本 /// </summary> /// <returns></returns> string GetVersion(); }}
显示效果:

<inheritdoc />
不指定 cref
仅限成员可用且所在的类型必须指定 <inheritdoc cref="" />
,这样才能自动识别。
6.5.31 启用 All Groups
分组功能
以下内容仅限 Furion v3.3.4+
版本使用。
有时候我们为了更好的对接口进行归类,配置了 Swagger
多个分组的功能,但这样也对生成客户端请求代码造成了困扰,所以添加了新的配置:
{ "SpecificationDocumentSettings": { "EnableAllGroups": true }}
6.5.32 接口过时控制
以下内容仅限 Furion v3.3.5+
版本使用。
有时候我们某个接口已经过时,提示尽早调用最新接口,只需要在方法上面贴 [Obsolete]
即可,如:
[Obsolete("GetName() 已经过时,请调用 GetFrameworkName() 替代")]public string GetName(){ return nameof(Furion);}[Obsolete]public string Other(){ // ...}

6.5.33 单一接口更多描述
以下内容仅限 Furion v3.3.5+
版本使用。
在该版本新增了 [ApiDescriptionSettings]
的 Description
属性,支持定义更多描述,如:
[ApiDescriptionSettings(Description = "我是一段描述,显示更多内容 <button>我是按钮</button>")]public string add(){ //....}

6.5.34 Swagger
异常/不能显示/错误处理
有时候可能因为错误的配置导致 Swagger
不能显示,这时候只需要复制提示的错误 .json
链接地址到浏览器中访问即可,如:
https://localhost:你的端口/swagger/Default/swagger.json
后面的 /swagger/Default/swagger.json
就是 Swagger
错误提示的 .json
链接地址。
这样就可以看到详细的错误了。


6.5.35 自定义 Swagger
的 SchemaId
以下内容仅限 Furion v3.6.4+
版本使用。
有时候,不同程序集会定义相同的类型名称 Name
,这样就会导致生成 Swagger
的 SchemaId
出现冲突,这时只需要在类型上贴 [SchemaId]
特性即可,如:
using Furion.SpecificationDocument;[SchemaId("Other_")]public class PersonDto{ // ...}
SchemaIdAttribute
配置选项:SchemaId
:自定义SchemaId
,字符串类型,只能是字母,数字,下划线
组合Replace
:是否完全替换,bool
类型,默认false
,默认是作为前缀拼接,如上面的PersonDto
会生成Other_PersonDto
,如果设置为true
,则直接使用Test_
6.5.36 自定义 Swagger
的 OperationId
以下内容仅限 Furion 4.1.7+
版本使用。
通过我们根据 swagger.json
生成前端代码时,Swagger
会自动根据路由地址生成调用的 api
名称,但这样的名称往往不易读,这时候可自定义 [OperationId]
来配置生成的前端名称。
using Furion.SpecificationDocument;public class PersonDto{ [OperationId("MyClientMethodName")] public string TestMethod() { // ... }}
6.5.37 Swagger
接口文档支持完整的 Markdown
在 Furion
最新版中,支持了完整的 Markdown
注册,如:
/// <summary>/// 测试 Markdown/// </summary>/// <remarks>/// # 先知 / Furion ([探索版](https://gitee.com/dotnetchina/Furion/tree/experimental/))////// 一个应用程序框架,您可以将它集成到任何.NET/C# 应用程序中。////// An application framework that you can integrate into any.NET/C# application.////// ## 安装 / Installation////// - [Package Manager] (https://www.nuget.org/packages/Furion)////// ```powershell/// Install-Package Furion/// ```////// - [.NET CLI] (https://www.nuget.org/packages/Furion)////// ```powershell/// dotnet add package Furion/// ```////// ## 例子 / Examples////// 我们在[主页](https://dotnetchina.gitee.io/furion)上有不少例子,这是让您入门的第一个:////// We have several examples [on the website] (https://dotnetchina.gitee.io/furion). Here is the first one to get you started:////// ```cs/// Serve.Run();////// [DynamicApiController]/// public class HelloService/// {/// public string Say()/// {/// return "Hello, Furion";/// }/// }/// ```////// 打开浏览器访问 `https://localhost:5001`。////// Open browser access `https://localhost:5001`.////// ## 文档 / Documentation////// 您可以在[主页] (https://dotnetchina.gitee.io/furion)或[备份主页](https://furion.icu)找到 Furion 文档。////// You can find the Furion documentation[on the website](https://dotnetchina.gitee.io/furion) or [on the backup website](https://furion.icu).////// ## 贡献 / Contributing////// 该存储库的主要目的是继续发展 Furion 核心,使其更快、更易于使用。 Furion 的开发在[Gitee](https://gitee.com/dotnetchina/Furion) 上公开进行,我们感谢社区贡献错误修复和改进。////// 阅读[贡献指南] (https://dotnetchina.gitee.io/furion/docs/contribute)内容,了解如何参与改进 Furion。////// The main purpose of this repository is to continue evolving Furion core, making it faster and easier to use.Development of Furion happens in the open on[Gitee] (https://gitee.com/dotnetchina/Furion), and we are grateful to the community for contributing bugfixes and improvements.////// Read[contribution documents] (https://dotnetchina.gitee.io/furion/docs/contribute) to learn how you can take part in improving Furion.////// ## 许可证 / License////// Furion 采用[MIT](https://gitee.com/dotnetchina/Furion/blob/net6/LICENSE) 开源许可证。////// Furion uses the[MIT] (https://gitee.com/dotnetchina/Furion/blob/net6/LICENSE) open source license.////// ```/// Copyright(c) 2020-2022 百小僧, Baiqian Co., Ltd./// Furion is licensed under Mulan PSL v2./// You can use this software according to the terms andconditions of the Mulan PSL v2./// You may obtain a copy of Mulan PSL v2 at:/// https://gitee.com/dotnetchina/Furion/blob/net6/LICENSE/// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUTWARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE./// See the Mulan PSL v2 for more details./// ```////// </remarks>/// <returns></returns>public string Hello(){ return "Furion";}

6.6 SpecificationDocumentSettings
配置
除了上述例子外,Furion
提供了一些配置选项,如:
DocumentTitle
:文档标题,string
,默认Specification Api Document
DefaultGroupName
:默认分组名,string
,默认Default
EnableAuthorized
:是否启用权限控制,bool
,默认true
FormatAsV2
:采用Swagger 2.0
版本,bool
,默认false
已弃用RoutePrefix
:规范化文档地址,string
,默认api
,如果希望在首页,改为空字符串即可。DocExpansionState
:文档显示方式,DocExpansion
,默认List
,取值:List
:列表式(展开子类),默认值Full
:完全展开None
:列表式(不展开子类)
XmlComments
:程序集注释描述文件名(可带.xml
,string
,默认Furion.Application, Furion.Web.Entry, Furion.Web.Core
GroupOpenApiInfos
:分组信息配置,SpecificationOpenApiInfo[]
,默认{ 'Group': 'Default'}
SecurityDefinitions
:安全策略定义配置,SpecificationOpenApiSecurityScheme[]
,默认[]
Servers
:配置 Server 下拉列表,OpenApiServer[]
类型,默认[]
,如:{Servers:[ { Url:"地址", Description:"描述"} ]}
HideServers
:是否隐藏 Server 下拉列表,bool
类型,默认true
RouteTemplate
:配置文档swagger.json
路由模板,默认模板:swagger/{documentName}/swagger.json
,{documentName}
代表分组名,必须保留原样PackagesGroups
:配置模块化内置分组名称,string[]
类型,默认[]
EnableEnumSchemaFilter
:启用枚举 Schema 筛选器,bool
类型,默认true
EnableTagsOrderDocumentFilter
:启用标签排序筛选器,bool
类型,默认true
ServerDir
:配置IIS
添加Application
部署名,string
类型,默认空,仅在 Furion v3.2.0+` 有效LoginInfo
:配置Swagger
是否需要登录才能访问,SpecificationLoginInfo
类型,默认null
,仅在 Furion v3.3.3+` 有效Enabled
:是否启用登录授权,默认false
CheckUrl
:检查登录状态的Url
地址,该地址必须是POST
请求,已授权返回200
,否则返回401
SubmitUrl
:提交登录的Url
地址,该地址必须是POST
请求且只有一个SpecificationAuth
类型参数,成功登录返回200
,否则返回401
,支持相对地址,以/
开头
EnableAllGroups
:启用Swagger
总分组功能,自动将所有分组的接口合并到All Groups
中,bool
类型,默认false
,仅在 Furion v3.3.4+` 有效
另外 SpecificationOpenApiInfo
内置配置如下:
Group
:分组唯一标识,string
类型,必填Order
:分组排序,int
类型,数字越大排前面,默认0
Visible
:配置分组是否可见,bool
类型,默认true
Title
:配置分组标题,string
类型Description
:配置分组描述,string
类型Version
:配置分组版本,默认1.0
TermsOfService
:配置相关链接地址,Uri
类型Contact
:配置联系方式,OpenApiContact
类型License
:配置协议,OpenApiLicense
类型
配置示例:
{ "SpecificationDocumentSettings": { "GroupOpenApiInfos": [ { "Group": "Group1", "Title": "分组标题", "Description": "这里是分组描述", "Version": "版本号", "TermsOfService": "https://furion.icu", "Contact": { "Name": "百小僧", "Url": "https://gitee.com/monksoul", "Email": "monksoul@outlook.com" }, "License": { "Name": "MIT", "Url": "https://gitee.com/dotnetchina/Furion/blob/alpha/LICENSE" } } ] }}
6.7 统一返回值模型/规范化结果/API 返回值
Furion
框架提供 规范化结果
功能,可以通过实现 IUnifyResultProvider
提供器实现统一规范化返回值定制,如:
- 定义结果包装类型
// 必须是泛型类型public class YourRESTfulResult<T>{ /// <summary> /// 状态码 /// </summary> public int? StatusCode { get; set; } /// <summary> /// 数据 /// </summary> public T Data { get; set; } /// <summary> /// 执行成功 /// </summary> public bool Succeeded { get; set; } /// <summary> /// 错误信息 /// </summary> public object Errors { get; set; } /// <summary> /// 附加数据 /// </summary> public object Extras { get; set; } /// <summary> /// 时间戳 /// </summary> public long Timestamp { get; set; }}
- 定义
IUnifyResultProvider
实现类,并贴特性[UnifyModel(typeof(YourRESTfulResult<>))]
using Furion.DataValidation;using Furion.DependencyInjection;using Furion.UnifyResult.Internal;using Microsoft.AspNetCore.Http;using Microsoft.AspNetCore.Mvc;using Microsoft.AspNetCore.Mvc.Filters;using System;using System.Threading.Tasks;namespace YourProject.UnifyResult{ /// <summary> /// RESTful 风格返回值 /// </summary> [UnifyModel(typeof(YourRESTfulResult<>))] public class YourRESTfulResultProvider : IUnifyResultProvider { /// <summary> /// 异常返回值 /// </summary> /// <param name="context"></param> /// <param name="metadata"></param> /// <returns></returns> public IActionResult OnException(ExceptionContext context, ExceptionMetadata metadata) { return new JsonResult(YourRESTfulResult(metadata.StatusCode, errors: metadata.Errors)); } /// <summary> /// 成功返回值 /// </summary> /// <param name="context"></param> /// <param name="data"></param> /// <returns></returns> public IActionResult OnSucceeded(ActionExecutedContext context, object data) { return new JsonResult(YourRESTfulResult(StatusCodes.Status200OK, true, data)); } /// <summary> /// 验证失败返回值 /// </summary> /// <param name="context"></param> /// <param name="metadata"></param> /// <returns></returns> public IActionResult OnValidateFailed(ActionExecutingContext context, ValidationMetadata metadata) { return new JsonResult(YourRESTfulResult(StatusCodes.Status400BadRequest, errors: metadata.ValidationResult)); } /// <summary> /// 特定状态码返回值 /// </summary> /// <param name="context"></param> /// <param name="statusCode"></param> /// <param name="unifyResultSettings"></param> /// <returns></returns> public async Task OnResponseStatusCodes(HttpContext context, int statusCode, UnifyResultSettingsOptions unifyResultSettings) { // 设置响应状态码 UnifyContext.SetResponseStatusCodes(context, statusCode, unifyResultSettings); switch (statusCode) { // 处理 401 状态码 case StatusCodes.Status401Unauthorized: await context.Response.WriteAsJsonAsync(YourRESTfulResult(statusCode, errors: "401 Unauthorized") , App.GetOptions<JsonOptions>()?.JsonSerializerOptions); break; // 处理 403 状态码 case StatusCodes.Status403Forbidden: await context.Response.WriteAsJsonAsync(YourRESTfulResult(statusCode, errors: "403 Forbidden") , App.GetOptions<JsonOptions>()?.JsonSerializerOptions); break; default: break; } } /// <summary> /// 返回 RESTful 风格结果集 /// </summary> /// <param name="statusCode"></param> /// <param name="succeeded"></param> /// <param name="data"></param> /// <param name="errors"></param> /// <returns></returns> private static YourRESTfulResult<object> YourRESTfulResult(int statusCode, bool succeeded = default, object data = default, object errors = default) { return new YourRESTfulResult<object> { StatusCode = statusCode, Succeeded = succeeded, Data = data, Errors = errors, Extras = UnifyContext.Take(), Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() }; } }}
之后在 Startup.cs
中注册即可:
services.AddControllers() .AddInjectWithUnifyResult<YourRESTfulResultProvider>();
默认情况下,规范化结果不会对 401
和 403
、404
状态码进行规范化处理,如需启动该状态码处理,只需在 Startup.cs
中的 Configure
中启用接口:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env){ if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } // 添加规范化结果状态码,需要在这里注册 app.UseUnifyResultStatusCodes(); // 其他注册...}
6.7.1 排除规范化处理
有些时候,我们某些接口不需要进行规范化处理,这时,我们只需要帖 [NonUnify]
特性即可。
6.7.2 规范化结果添加额外数据
默认的规范化结果中包含 extras
属性,可以配置额外数据返回到客户端:
UnifyContext.Fill(new { Message = "操作成功" });
6.7.3 自定义特别接口规范化结果
有些时候,我们特定接口需返回特定的接口类型,无需规范化处理,这时候我们只需要贴 [UnifyResult(typeof(结果类))]
或 [ProducesResponseType(typeof(结果类),200)]
,如:
[UnifyResult(typeof(Person))]public Person GetPerson(int id){ // ...}
6.8 反馈与建议
给 Furion 提 Issue。