.NET Core基礎篇之:集成Swagger文檔與自定義Swagger UI
Swagger
大家都不陌生,Swagger (OpenAPI)
是一個與程式語言無關的介面規範,用於描述項目中的 REST API
。它的出現主要是節約了開發人員編寫介面文檔的時間,可以根據項目中的注釋生成對應的可視化介面文檔。
OpenAPI 規範 (openapi.json)
OpenAPI
規範是描述 API
功能的文檔。該文檔基於控制器和模型中的 XML
和屬性
注釋。它是 OpenAPI
流的核心部分,用於驅動諸如 SwaggerUI
之類的工具。
.NET
平台下的兩個主要實現Swagger
的包是 Swashbuckle 和 NSwag。今天我們從 Swashbuckle
開始了解。
基礎功能
1、在包管理器搜索Swashbuckle.AspNetCore並安裝。
2、在Startup.cs文件內的ConfigureServices方法內添加程式碼。
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen();
}
3、在Startup.cs文件內的Configure方法內添加程式碼。
app.UseSwagger();
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "v1");
options.RoutePrefix = string.Empty;
});
4、修改項目的launchSettings.json文件,將launchUrl的值改為:index.html
5、準備介面
[ApiController]
public class HomeController : ControllerBase
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
/// <summary>
/// 獲取用戶資訊
/// </summary>
/// <returns></returns>
[HttpGet("home/getuser")]
public string GetUser()
{
return "my name is dotnetboy";
}
/// <summary>
/// 登錄成功
/// </summary>
/// <returns></returns>
[HttpPost("home/login")]
public string Login()
{
return "login success";
}
/// <summary>
/// 刪除用戶
/// </summary>
[HttpDelete("home/{id}")]
public string DeleteUser(string id)
{
return $"delete success,id={id}";
}
}
6、開啟xml文檔輸出然後啟動項目
擴展功能
項目描述
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo
{
Title = "測試介面文檔",
Version = "v1",
Description = "測試 webapi"
});
});
介面分組
在實際開發中,如果所有介面都展示在一起非常不利於相關人員查找,我們可以根據業務邏輯對相關介面進行分組,比如:登錄、用戶、訂單、商品等等。
1、準備分組資訊特性
/// <summary>
/// 分組資訊特性
/// </summary>
public class GroupInfoAttribute : Attribute
{
/// <summary>
/// 標題
/// </summary>
public string Title { get; set; }
/// <summary>
/// 版本
/// </summary>
public string Version { get; set; }
/// <summary>
/// 描述
/// </summary>
public string Description { get; set; }
}
2、準備分組枚舉
/// <summary>
/// 介面分組枚舉
/// </summary>
public enum ApiGroupNames
{
[GroupInfo(Title = "登錄認證", Description = "登錄相關介面", Version = "v1")]
Login,
[GroupInfo(Title = "User", Description = "用戶相關介面")]
User,
[GroupInfo(Title = "User", Description = "訂單相關介面")]
Order
}
3、準備介面特性
/// <summary>
/// 分組介面特性
/// </summary>
public class ApiGroupAttribute : Attribute, IApiDescriptionGroupNameProvider
{
/// <summary>
///
/// </summary>
/// <param name="name"></param>
public ApiGroupAttribute(ApiGroupNames name)
{
GroupName = name.ToString();
}
/// <summary>
/// 分組名稱
/// </summary>
public string GroupName { get; set; }
}
4、給不同介面加上特性
[ApiController]
public class HomeController : ControllerBase
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
/// <summary>
/// 獲取用戶資訊
/// </summary>
/// <returns></returns>
[HttpGet("home/getuser")]
[ApiGroup(ApiGroupNames.User)]
public string GetUser()
{
return "my name is dotnetboy";
}
/// <summary>
/// 登錄成功
/// </summary>
/// <returns></returns>
[HttpPost("home/login")]
[ApiGroup(ApiGroupNames.Login)]
public string Login()
{
return "login success";
}
/// <summary>
/// 刪除訂單
/// </summary>
[HttpDelete("home/{id}")]
[ApiGroup(ApiGroupNames.Order)]
public string DeleteOrder(string id)
{
return $"delete success,id={id}";
}
/// <summary>
/// 留言
/// </summary>
[HttpDelete("home/message")]
public string DeleteUser(string msg)
{
return $"message:{msg}";
}
}
5、修改 ConfigureServices 方法的 AddSwaggerGen
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo
{
Title = "介面文檔",
Version = "v1",
Description = "測試 webapi"
});
// 遍歷ApiGroupNames所有枚舉值生成介面文檔,Skip(1)是因為Enum第一個FieldInfo是內置的一個Int值
typeof(ApiGroupNames).GetFields().Skip(1).ToList().ForEach(f =>
{
//獲取枚舉值上的特性
var info = f.GetCustomAttributes(typeof(GroupInfoAttribute), false).OfType<GroupInfoAttribute>().FirstOrDefault();
options.SwaggerDoc(f.Name, new OpenApiInfo
{
Title = info?.Title,
Version = info?.Version,
Description = info?.Description
});
});
// 沒有特性的介面分到NoGroup上
options.SwaggerDoc("NoGroup", new OpenApiInfo
{
Title = "無分組"
});
// 判斷介面歸於哪個分組
options.DocInclusionPredicate((docName, apiDescription) =>
{
if (docName == "NoGroup")
{
// 當分組為NoGroup時,只要沒加特性的介面都屬於這個組
return string.IsNullOrEmpty(apiDescription.GroupName);
}
else
{
return apiDescription.GroupName == docName;
}
});
});
6、修改 Configure 方法的 UseSwaggerUI
app.UseSwaggerUI(options =>
{
// 遍歷ApiGroupNames所有枚舉值生成介面文檔
typeof(ApiGroupNames).GetFields().Skip(1).ToList().ForEach(f =>
{
//獲取枚舉值上的特性
var info = f.GetCustomAttributes(typeof(GroupInfoAttribute), false).OfType<GroupInfoAttribute>().FirstOrDefault();
options.SwaggerEndpoint($"/swagger/{f.Name}/swagger.json", info != null ? info.Title : f.Name);
});
options.SwaggerEndpoint("/swagger/NoGroup/swagger.json", "無分組");
options.RoutePrefix = string.Empty;
});
自定義UI
前幾天,前端同事和我吐槽,Swagger
的原生UI
太丑了,又不夠直觀,想找個介面還得一個個收縮展開,總之就是很難用。
- 不夠直觀
- 不方便查找
有了上面的兩點需求何不自己實現一套UI
呢?(最終還是用了第三方現成的)
文章最開始有提到OpenAPI
對應的 json
內容,大家也可以在瀏覽器的控制台看看,swagger ui
的數據源都來自於一個叫 swagger.json
的文件,數據源都有了,根據數據源再做一套 UI
也就不是什麼難事了。
1、準備一個美觀的單頁面(網上找的)
2、將單頁面相關內容放到項目內(記得開啟靜態文件讀取)
app.UseStaticFiles();
3、將單頁面指定為 UI 頁面。
app.UseSwaggerUI(options =>
{
options.IndexStream = () => GetType().Assembly.GetManifestResourceStream("h.swagger.Swagger.index.html");
});
4、在單頁面內處理 swagger.json 數據源。
5、最終效果
Swagger UI
的功能還是比較多的,比如:詳情、調試。如果想自己實現一套UI
要做的工作還很多。所以,拿來主義永不過時,最終我還是選擇了第三方開源的項目:Knife4j
。
使用起來也是非常簡單,先引用包:IGeekFan.AspNetCore.Knife4jUI
,然後在Startup.Configure
中將 app.UseSwaggerUI
替換為:
app.UseKnife4UI(c =>
{
c.RoutePrefix = string.Empty;
c.SwaggerEndpoint($"/swagger/v1/swagger.json", "h.swagger.webapi v1");
});