在.NET?Core?Web?API中完美配置Swagger文檔的方法
新建項(xiàng)目
打開visual studio創(chuàng)建新項(xiàng)目,這里我們選擇.net core web api模板,然后輸入項(xiàng)目名稱及其解決方案創(chuàng)建新項(xiàng)目


這里使用配置一些其他信息,根據(jù)自己情況進(jìn)行選擇:

創(chuàng)建好項(xiàng)目之后我們可以看到 web api 模板運(yùn)行的項(xiàng)目,相比于MVC模式開發(fā)的項(xiàng)目,初始文件是保留原有的控制器文件但是刪除了模型和視圖文件,而且還加上了兩個(gè)文件,文件的作用相當(dāng)于測(cè)試用例一一可以模擬發(fā)起請(qǐng)求,如下所示:

我們直接運(yùn)行該項(xiàng)目,可以看到我們打開了一個(gè)Swagger文件,對(duì)于后端小白來說可能不太熟悉這個(gè)文件的作用,但是對(duì)于前端開發(fā)者來講可謂是非常熟悉的東西,前端開發(fā)調(diào)用接口就需要經(jīng)常和這個(gè)文件打交道,如下所示:

我們除了可以在Swagger上測(cè)試接口,也可以在本地代碼的測(cè)試用例處點(diǎn)擊發(fā)起請(qǐng)求進(jìn)行測(cè)試:

這里做一個(gè)演示,比如說我們想在Swagger文檔中新增一組接口的話,我們可以在控制器文件中設(shè)置一下get、post、delete、put請(qǐng)求操作,如下我們將原本的文件復(fù)制一份然后命名為First,然后設(shè)置一下接口類型,如下所示:

重新運(yùn)行我們的項(xiàng)目然后打開Swagger,可以看到我們創(chuàng)建的一組接口成功出現(xiàn)了,這里接口的組名可以看到是 FirstController.cs 文件中Controller的前綴,非常好識(shí)別:

RestFul
背景:近些年來隨著移動(dòng)互聯(lián)網(wǎng)的發(fā)展,前端設(shè)備層出不窮(手機(jī)、平板、桌面電腦、其他專用設(shè)備..),因此必須有一組統(tǒng)一的機(jī)制方便不同的前端設(shè)備與后端進(jìn)行通信,于是RestFul誕生了,它可以通過一套統(tǒng)一的接口為Web,iOS和Android等各種各樣的終端提供服務(wù)。
特點(diǎn):RestFul把控制器作為維度當(dāng)成一塊資源,對(duì)于這個(gè)資源會(huì)進(jìn)行增刪改查等各種當(dāng)作,這些動(dòng)作必須都得有唯一的URL地址來匹配請(qǐng)求的Method的類型(get、post、put、delete),本質(zhì)上就是用URL定位資源,用HTTP(get、post、put、delete)描述操作。說白了就是一種軟件架構(gòu)設(shè)計(jì)風(fēng)格而不是標(biāo)準(zhǔn),只是提供了一組設(shè)計(jì)原則和約束條件,主要用于客戶端和服務(wù)器交互類的軟件,基于這個(gè)風(fēng)格設(shè)計(jì)的軟件可以更簡(jiǎn)潔有層次,更易于實(shí)現(xiàn)緩存等機(jī)制。
比如上文我們?cè)诳刂破魑募性O(shè)置了一組接口,如果我們?cè)僭谖募刑砑颖热缯f一個(gè)get接口請(qǐng)求,運(yùn)行項(xiàng)目其實(shí)是會(huì)報(bào)錯(cuò)的,為什么?就是因?yàn)檫@兩個(gè)get請(qǐng)求的地址都是一樣的,編輯器沒法識(shí)別到底哪個(gè)get請(qǐng)求是你想要的,為了區(qū)分我們必須設(shè)置唯一的URL地址來避免報(bào)錯(cuò),如下:

重新運(yùn)行項(xiàng)目,可以看到我們?cè)贔irst組當(dāng)中又新增了一個(gè)新的get請(qǐng)求,且兩個(gè)get請(qǐng)求的URL路徑是不一致的,如下所示:

對(duì)于路由約束的類型我們可以參考如下表格,這些都可以作為接口傳參的一個(gè)類型限定:
| 限制 | 示例 | 匹配示例 | 說明 |
|---|---|---|---|
| int | {id: int} | 123456789, -123456789 | 匹配任何整數(shù) |
| bool | {active: bool} | true, false | 匹配true或false,忽略大小寫 |
| datetime | {dob: datetime} | 2024-12-11,2024-12-12 7:32pm | 匹配滿足datetime類型的值 |
| decimal | {price: decimal} | 49.99, -1,000.01 | 匹配滿足decimal類型的值 |
| double | {height: double} | 1234, -1001.01e8 | 匹配滿足double類型的值 |
| float | {height: float} | 1234, -1001.01e8 | 匹配滿足float類型的值 |
| long | {ticks: long} | 123456789, -123456789 | 匹配滿足long類型的值 |
| minlength(value) | {usename: minlength(4)} | KOBE | 字符串長(zhǎng)度不能小于4個(gè)字符 |
| maxlength(value) | {filename: maxlength(8)} | CURRY | 字符串長(zhǎng)度不能超過8個(gè)字符 |
| length(value) | {filename: length(12)} | somefile.txt | 字符串長(zhǎng)度必須是12個(gè)字符 |
| length(min,max) | {filename: length(8,16)} | somefile.txt | 字符串長(zhǎng)度必須介于8和16之間 |
| min(value) | {age: min(18)} | 20 | 整數(shù)值必須大于18 |
| max(value) | {age: max(120)} | 119 | 整數(shù)值必須小于120 |
| range(min, max) | {age: range(18, 120)} | 100 | 整數(shù)值必須介于18和120之間 |
| alpha | {name: alpha} | Rick | 字符串必須由一或多a-z字母組成 |
| regex(expression) | {ssn:regex(^\d{3})} | 3 | 字符串必須匹配指定的正則 |
| required |
Swagger配置
雖然上面我設(shè)置了Swagger并成功運(yùn)行了,但是設(shè)想一個(gè)場(chǎng)景,如果你是后端你寫的代碼你當(dāng)然看的懂,生成的Swagger接口也是知道是什么意思,但是你把這個(gè)Swaager丟給前端,前端是否看的懂呢?如果看不懂是不是還要找后端溝通,這樣就增加了時(shí)間成本。所以后端不僅僅要不接口寫對(duì),還要把Swagger文檔寫好,這里我們就需要對(duì)其進(jìn)行相應(yīng)配置,爭(zhēng)取讓其他人看懂自己寫的接口,這才是真正意義上一名后端應(yīng)該做的事情,如下所示:
注釋展示
注釋是很重要的,當(dāng)我們寫完一個(gè)接口之后我們就需要對(duì)這個(gè)接口的作用進(jìn)行注釋,用來告訴前端后端給的這個(gè)接口作用和意義是什么,如何設(shè)置Swagger注釋展示呢?請(qǐng)往下看:
如下我們給接口代碼寫下注釋,注釋的快捷鍵是///,也就是三個(gè)斜杠即可生成,然后右鍵項(xiàng)目點(diǎn)擊屬性,勾選文檔文件這個(gè)復(fù)選框:


我們右鍵項(xiàng)目重新生成解決方案然后打開我們的項(xiàng)目資源管理目錄,可以看到在我們項(xiàng)目的obj目錄下的最里層有生成了一個(gè)xml文件,右鍵選擇文本打開可以看到我們的注釋就在里面:


接下來如果說我們想把注釋展示到Swagger文檔中的話,我們需要來到入口文件Program.cs對(duì)我們的Swagger進(jìn)行一個(gè)配置,給原本的AddSwaggerGen添加一個(gè)配置對(duì)象,代碼如下:

builder.Services.AddSwaggerGen(option => {
#region 注釋展示
{
// 獲取應(yīng)用程序所在目錄(絕對(duì),不受工作目錄影響,建議采用此方法獲取路徑)
string basePath = AppContext.BaseDirectory;
string xmlPath = Path.Combine(basePath, "netCoreWebApi.xml");
option.IncludeXmlComments(xmlPath);
}
#endregion
});回到Swagger文檔中可以看到我們的注釋已經(jīng)成功的被渲染出來了,方便前端的理解:

版本控制
隨著項(xiàng)目不斷升級(jí)和開發(fā)的過程中,我們還可能需要去對(duì)項(xiàng)目進(jìn)行開發(fā)多個(gè)版本,但是版本之間的Swagger是不同的,不會(huì)放置在同一個(gè)Swagger文檔下面,我們打開Swagger文檔也能看到右上角有個(gè)下拉框,其就是支持不同的版本的切換的,如何做?請(qǐng)往下看:
為了方便不同版本的切換,這里我們直接在解決方案中新建項(xiàng)目設(shè)置一個(gè)獨(dú)立的文件夾出來,因?yàn)榇龝?huì)我們還要對(duì)其作一個(gè)擴(kuò)展,所以這里我們選擇一個(gè)類庫(kù)即可,如下:


生成的文件我們重命名為 ApiVersionInfo ,然后設(shè)置靜態(tài)成員V1到V5表明版本有5個(gè),如下所示:

我們來到入口文件Program.cs文件處,這里我們開始設(shè)置支持Swagger版本控制的代碼,這里我們借助 System.Reflection 中的FieldInfo反射機(jī)制中的類型,來獲取類型ApiVersionInfo中的所有字段信息,然后通過OpenApiInfo來描述Swagger文檔的元數(shù)據(jù)及包含了有關(guān)API的關(guān)鍵信息,比如標(biāo)題、版本、描述等,如下所示:

builder.Services.AddSwaggerGen(option => {
#region 注釋展示
{
// 獲取應(yīng)用程序所在目錄(絕對(duì),不受工作目錄影響,建議采用此方法獲取路徑)
string basePath = AppContext.BaseDirectory;
string xmlPath = Path.Combine(basePath, "netCoreWebApi.xml");
option.IncludeXmlComments(xmlPath);
}
#endregion
#region 支持Swagger版本控制
{
foreach (FieldInfo filed in typeof(ApiVersionInfo).GetFields())
{
option.SwaggerDoc(filed.Name, new OpenApiInfo()
{
Title = $"netCoreWebApi API {filed.Name}",
Version = filed.Name,
Description = $"netCoreWebApi API {filed.Name} 版本"
});
}
}
#endregion
});接下來配置Swagger UI使得每個(gè)API版本都有一個(gè)對(duì)應(yīng)的Swagger UI頁(yè)面,具體來說它會(huì)為每個(gè)API版本動(dòng)態(tài)創(chuàng)建一個(gè)Swagger UI的入口從而允許用戶查看不同版本的API文檔,如下:

接下來我們來到編寫接口代碼的控制器文件,給不同版本設(shè)置如下代碼,作用是將特定的API控制器或者方法標(biāo)記為屬于某個(gè)版本組,從而使得Swagger等工具能夠按版本組織和展示API文檔:

最終呈現(xiàn)的效果如下所示:

Token傳值
如果項(xiàng)目的接口需要授權(quán)才能被訪問的話,這里我們就需要通過token傳值的方式來進(jìn)行鑒權(quán)才能調(diào)試接口,如何做呢?請(qǐng)往下看:
這里我們?nèi)匀辉赟wagger配置函數(shù)中設(shè)置token傳值以及添加對(duì)應(yīng)的安全要求,如下所示:

#region 支持token傳值
{
option.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
{
Description = "JWT授權(quán)(數(shù)據(jù)將在請(qǐng)求頭中進(jìn)行傳輸) 參數(shù)結(jié)構(gòu): \"Authorization: Bearer {token}\"", // 描述
Name = "Authorization", // 授權(quán)名稱
In = ParameterLocation.Header, // 授權(quán)位置,放在頭信息進(jìn)行傳值
Type = SecuritySchemeType.ApiKey, // 授權(quán)類型
BearerFormat = "JWT", // 格式是JWT
Scheme = "Bearer"
});
// 添加安全要求
option.AddSecurityRequirement(new OpenApiSecurityRequirement()
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference()
{
Id = "Bearer", // 必須和上面一致
Type = ReferenceType.SecurityScheme
}
},
new string[] { }
}
});
}
#endregion運(yùn)行項(xiàng)目來到Swagger文檔中,可以看到我們已經(jīng)成功添加了身份驗(yàn)證,這里我們輸入對(duì)應(yīng)的JWT格式即可,如下所示我們輸入token之后發(fā)起請(qǐng)求,如下已經(jīng)帶上了我們?cè)O(shè)置的token:


方法封裝
根據(jù)上面對(duì)Swagger的配置,可以看到我們對(duì)Swagger的配置基本上都寫在了入口Program.cs文件當(dāng)中,這樣就顯得非常的冗余,入口文件代碼量太多了,這里我們可以將對(duì)Swagger的配置抽離到我們創(chuàng)建的類庫(kù)當(dāng)中,新建一個(gè)文件夾用于專門存放Swagger配置的東西,如下所示:

這里設(shè)置一個(gè)函數(shù)然后把IServiceCollection設(shè)置為Service的類型,該類型用于配置依賴注入容器的接口,通常為Swagger配置服務(wù),我們直接把入口文件當(dāng)中配置Swagger的代碼直接粘貼過來:
using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
namespace netCoreWebApi.WebCore.SwaggerExt
{
public static class SwaggerExtension
{
public static void AddSwaggerExtension(this IServiceCollection Service)
{
Service.AddEndpointsApiExplorer();
Service.AddSwaggerGen(option => {
#region 注釋展示
{
// 獲取應(yīng)用程序所在目錄(絕對(duì),不受工作目錄影響,建議采用此方法獲取路徑)
string basePath = AppContext.BaseDirectory;
string xmlPath = Path.Combine(basePath, "netCoreWebApi.xml");
option.IncludeXmlComments(xmlPath);
}
#endregion
#region 支持Swagger版本控制
{
foreach (FieldInfo filed in typeof(ApiVersionInfo).GetFields())
{
option.SwaggerDoc(filed.Name, new OpenApiInfo()
{
Title = $"netCoreWebApi API {filed.Name}",
Version = filed.Name,
Description = $"netCoreWebApi API {filed.Name} 版本"
});
}
}
#endregion
#region 支持token傳值
{
option.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
{
Description = "JWT授權(quán)(數(shù)據(jù)將在請(qǐng)求頭中進(jìn)行傳輸) 參數(shù)結(jié)構(gòu): \"Authorization: Bearer {token}\"", // 描述
Name = "Authorization", // 授權(quán)名稱
In = ParameterLocation.Header, // 授權(quán)位置,放在頭信息進(jìn)行傳值
Type = SecuritySchemeType.ApiKey, // 授權(quán)類型
BearerFormat = "JWT", // 格式是JWT
Scheme = "Bearer"
});
// 添加安全要求
option.AddSecurityRequirement(new OpenApiSecurityRequirement()
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference()
{
Id = "Bearer", // 必須和上面一致
Type = ReferenceType.SecurityScheme
}
},
new string[] { }
}
});
}
#endregion
});
}
public static void UseSwaggerExtension(this WebApplication app)
{
app.UseSwagger();
app.UseSwaggerUI(option => {
foreach (FieldInfo filed in typeof(ApiVersionInfo).GetFields())
{
option.SwaggerEndpoint($"/swagger/{filed.Name}/swagger.json", filed.Name);
}
});
}
}
}這里還需要在類庫(kù)中安裝一下主程序當(dāng)中包,這里注意意義名稱和版本號(hào):

因?yàn)閠his修飾靜態(tài)類中的靜態(tài)方法,上面創(chuàng)建的兩個(gè)方法都是靜態(tài)類中的靜態(tài)方法同時(shí)第一個(gè)參數(shù)還用this進(jìn)行修飾,這種擴(kuò)展方法可以把傳參提到前面當(dāng)成實(shí)例方法來進(jìn)行調(diào)用,接下來我們就在入口文件中調(diào)用這兩個(gè)方法:

最后我們重新運(yùn)行項(xiàng)目,如下可以看到我們的Swagger也可以被重新運(yùn)行:

到此這篇關(guān)于如何在.NET Core Web API中完美配置Swagger文檔的文章就介紹到這了,更多相關(guān).NET Core Web API 配置Swagger文檔內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Could not load file or assembly "App_Licenses.dll"
Could not load file or assembly "App_Licenses.dll"的問題2010-03-03
淺析Repeater控件的使用 (原樣導(dǎo)出和動(dòng)態(tài)顯示/隱藏Repeater中的列)
本文主要介紹了淺析Repeater控件的使用 (原樣導(dǎo)出和動(dòng)態(tài)顯示/隱藏Repeater中的列)的具體方法,需要的朋友可以看下2016-12-12
.net Core 3.0 WebApi 創(chuàng)建Linux守護(hù)進(jìn)程的方法
這篇文章主要介紹了.net Core 3.0 WebApi 創(chuàng)建Linux守護(hù)進(jìn)程的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03

