爲控制器生成OpenAPI註釋

非常喜歡. NET 的 /// 註釋,寫代碼的時候就順道完成寫文檔的過程,簡直不要太爽了。 ASP. NET CORE 也是一樣的,通過 Swagger 工具,可以自動生成 API 的接口文檔(OpenAPI規範),提供給前端使用,也可以用過 APIPOST/APIFOX 之類的工具提供給前端同學直接調用。

生成 OpenAPI 註釋

只需要安裝 swashbuckle.aspnetcore 包,在項目上設置生成 XML 格式的註釋,並且如下配置即可自動生成 OpenAPI 的文檔,對我這個例子,可以通過 swagger/v{version}/swagger.json 訪問。

            services.AddSwaggerGen(options =>
            {
                // options.CustomSchemaIds(type => type.AssemblyQualifiedName);
                var fileName = Assembly.GetExecutingAssembly().GetName().Name + ".xml";
                var filePath = Path.Combine(AppContext.BaseDirectory, fileName);

                // integrate xml comments
                options.IncludeXmlComments(filePath);
            });


                app.UseSwagger();
                app.UseSwaggerUI(
                    options =>
                    {
                        foreach (var description in app.DescribeApiVersions())
                        {
                            var url = $"/swagger/{description.GroupName}/swagger.json";
                            var name = description.GroupName.ToUpperInvariant();
                            options.SwaggerEndpoint(url, name);
                        }
                    });

註釋如下:

    /// <summary>
    /// 這個接口
    /// </summary>
    public class CoverageDataController : ODataController
	{
        /// <summary>
        /// 獲取蓋度數據
        /// </summary>
        /// <param name="key"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        [HttpGet]
        [ProducesResponseType(typeof(CoverageDataDto), Status200OK)]
        public async Task<IActionResult> Get(string key, ODataQueryOptions<CoverageDataDto> options)
        {
        }
    }

生成 Tags 註釋

在使用 APIFOX 導入 swagger.json 導入時,我發現,對每一個 path 的註釋能夠正常顯示,但是對的控制器的註釋不能正常被識別。

image

查看生成的 swagger.json,這個 CoverageData 被解釋成了 OpenAPI 的 Tags,那對應控制器的相關注釋,是需要使用另外的標註實現的,而不能直接使用///的註釋實現。

paths": {
        "/api/v{version}/CoverageData({key})": {
            "get": {
                "tags": [
                    "CoverageData"
                ],
                "summary": "獲取蓋度數據",

安裝的新的包 swashbuckle.aspnetcore.annotations,然後增加啓用語句,如下:

            services.AddSwaggerGen(options =>
            {
                // options.CustomSchemaIds(type => type.AssemblyQualifiedName);
                var fileName = Assembly.GetExecutingAssembly().GetName().Name + ".xml";
                var filePath = Path.Combine(AppContext.BaseDirectory, fileName);

                // integrate xml comments
                options.IncludeXmlComments(filePath);
                options.EnableAnnotations();
            });

在控制器的聲明上面,添加 [SwaggerTag("接受蓋度數據")] 註解:

    /// <summary>
    /// 這個接口
    /// </summary>
    [SwaggerTag("接受蓋度數據")]
    public class CoverageDataController : ODataController
	{
    }

最後生成的 swagger.json 文件在末尾多了幾行:

    "tags": [
        {
            "name": "CoverageData",
            "description": "接受蓋度數據"
        }
    ]

Swagger 裏面就可以看到註釋了:

image

但是導入到 APIFOX 中,顯示的組別名稱依然是 CoverageData ,沒有達到我想要的效果,我想將其替換成可以顯示友好的名稱。實質上是爲 CoverageData 取一個別名。

注:這種方法不能與 swagger 配置的 TagActionsBy 方法的一起使用。

Tags 註解

在 ASP. NET CORE 中,可以在控制器上使用 [Tags("蓋度接口")],對控制器的組別進行標註。這樣生成的 tag 名稱直接就換成了的中文名稱。

"paths": {
        "/api/v{version}/CoverageData({key})": {
            "get": {
                "tags": [
                    "蓋度接口"
                ],
                "summary": "獲取蓋度數據",

....

    "tags": [
        {
            "name": "CoverageData",
            "description": "接受蓋度數據"
        }
    ]

但是 swagger 變得非常奇怪:

image

出現了兩個不同的 tag,其中 CoverageData 名稱的下面沒有從屬的 api。

如果沒有對 Tag 寫 description 的要求,那麼使用這個方案是最簡單的:設置[Tags],不要設置[SwaggerTag]。

DisplayName 註解

這麼看應該是通過 swagger 生成的 tag 與通過 [Tags] 註解生成的 tag 對象不能匹配,導致 swagger 生成的沒用被引用。

查了很久資料,說這個是一個現在的 Bug,有人通過重寫 DisplayName,在帖子中給了臨時的解決方案

  1. 先增加一個新的類型。
/// <summary>
/// Uses the [DisplayName] attribute as the Controller name in OpenAPI spec and Swagger/ReDoc UI if available else the default Controller name.
/// </summary>
public class ControllerDocumentationConvention : IControllerModelConvention
{
    void IControllerModelConvention.Apply(ControllerModel controller)
    {
        if (controller == null)
        {
            return;
        }
        
        foreach (var attribute in controller.Attributes)
        {
            if (attribute is DisplayNameAttribute displayNameAttribute && !string.IsNullOrWhiteSpace(displayNameAttribute.DisplayName))
            {
                controller.ControllerName = displayNameAttribute.DisplayName;
            }
        }
    }
}
  1. 給 Controller 配置這個命名轉換。
services.AddControllers(o =>
{
   o.Conventions.Add(new ControllerDocumentationConvention());
});
  1. 在需要調整名稱的控制器上添加 [DisplayName("targetNames")] 即可。可以看到名稱與註釋都得到的保留,最終效果如下:

image

導入 APIFOX 也可以正常識別了。

image

參考資料

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章