ASP.NET Core Web API Swagger 按標籤Tags分組排序顯示

需求

  1. swagger頁面按標籤Tags分組顯示。
  2. 沒有打標籤Tags的接口,默認歸到"未分組"。
  3. 分組內按接口路徑排序

說明

爲什麼沒有使用GroupName對接口進行分組?
暫時不需要,以及不想點擊swagger頁面右上角那個下拉框。
當然Tags和GroupName不衝突,不影響通過GroupName再分組顯示。

如何實現

1. 爲controller或action打上標籤

TagsAttribute特性可以打在controller類上,也可以打在action方法上,一個類或方法上可以打多個標籤。示例:

[Tags("標籤1", "標籤2")]

有個小坑,Tags要麼打在controller上,要麼打在action上,不能同時打。

2. 實現IDocumentFilter接口

清空原有的Tags,並按接口類或方法上的標籤重新添加Tags,然後排序。

using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using Utils;

namespace DotnetDatamining.Filters
{
    /// <summary>
    /// Workaround for https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/2162
    /// When adding XML controller descriptions to the swagger description document,
    /// controllers are listed out of alphabetical order.
    ///
    /// This filter explicitly reorders them.
    /// </summary>
    public class TagReorderDocumentFilter : IDocumentFilter
    {
        /// <summary>
        /// Allows customization of the swagger description document
        /// </summary>
        /// <param name="swaggerDoc">The generated swagger description document</param>
        /// <param name="context">Context information</param>
        public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
        {
            swaggerDoc.Tags.Clear(); //清空Tags

            //重新添加Tags
            foreach (var path in swaggerDoc.Paths)
            {
                foreach (var o in path.Value.Operations)
                {
                    foreach (var tag in o.Value.Tags)
                    {
                        swaggerDoc.Tags.Add(tag);
                    }
                }
            }

            //排序
            swaggerDoc.Tags = swaggerDoc.Tags
                .OrderBy(tag => TinyPinYinUtil.GetPinYin(tag.Name)) //按漢字拼音排序
                .ToList();
        }
    }
}

3. Swagger配置

//swagger配置
builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo
    {
        Title = "XXX",
        Version = "1.0",
        Description = "XXX"
    });
    var path = Path.Combine(AppContext.BaseDirectory, "DotnetDatamining.xml"); // xml文檔絕對路徑
    c.IncludeXmlComments(path, true); // 顯示控制器層註釋
    c.TagActionsBy(a =>
    {
        var tagAttr = a.ActionDescriptor.EndpointMetadata.OfType<TagsAttribute>().FirstOrDefault();
        if (tagAttr != null)
        {
            return tagAttr.Tags.ToList();
        }
        return new List<string>() { "未分組" };
    });
    c.DocumentFilter<TagReorderDocumentFilter>(); // Workaround: After adding XML controller descriptions, they are listed out of alphabetical order
    c.OrderActionsBy(a => a.RelativePath); // 對Action排序
});

上述代碼說明

(1) 使用TagReorderDocumentFilter過濾器

c.DocumentFilter<TagReorderDocumentFilter>();

(2) 對Action按標籤分組

沒有打標籤Tags的接口,默認歸到"未分組"。

c.TagActionsBy(a =>
{
    var tagAttr = a.ActionDescriptor.EndpointMetadata.OfType<TagsAttribute>().FirstOrDefault();
    if (tagAttr != null)
    {
        return tagAttr.Tags.ToList();
    }
    return new List<string>() { "未分組" };
});

(2) 分組內對Action按接口路徑排序

c.OrderActionsBy(a => a.RelativePath);

效果圖

分組按漢字拼音排序,分組內按接口路徑排序

在實現過程中遇到的問題

  1. 部署到linux系統,中文拼音排序問題,不想修改linux系統配置,於是修改代碼,通過TinyPinyin.Net庫實現。
  2. 分組排序和分組內接口排序問題
    一個接口可以打多個標籤。如果是單個標籤,可以通過OrderActionsBy對分組和接口同時排序。如果是多個標籤,則無法通過OrderActionsBy對分組和接口同時排序,只能對接口進行排序。
    可以在TagReorderDocumentFilter過濾器中對標籤進行排序,但Tags中都是controller默認的標籤,所以要先清空,再重新添加,然後再排序。

爲了解決這些問題,提供一個容易閱讀和查找的swagger文檔目錄,斷斷續續花費了很長時間纔算解決。

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