基於 abp vNext 和 .NET Core 開發博客項目 - 再說Swagger,分組、描述、小綠鎖

在開始本篇正文以前,解決一個 @瘋瘋過 指出的錯誤,再次感謝指正。html

0

步驟以下:git

  • 刪掉.Domain.Shared層中的項目引用,添加nuget依賴包Volo.Abp.Identity.Domain.Shared,可使用命令:Install-Package Volo.Abp.Identity.Domain.Shared
  • .Domain層中引用項目.Domain.Shared,在模塊類中添加依賴typeof(MeowvBlogDomainSharedModule)
  • .EntityFrameworkCore層中的引用項目.Domain.Shared改爲.Domain

0


上一篇文章(http://www.javashuo.com/article/p-rtnsqrfg-kp.html)完成了對API返回模型的封裝,緊接着我打算繼續來折騰一下Swagger,以前的文章中已經簡單用起了Swagger,本篇仍是圍繞它讓其發揮更高的更多的價值。github

當咱們的項目不斷壯大,API持續增多,這時若是想要快速準肯定位到某個API可能不是那麼容易,須要翻半天才能找對咱們的API。因而對Swagger API文檔分組和詳細的文檔描述就有必要了,就本項目而言,博客系統能夠分組爲:博客前臺接口、博客後臺接口、其它公共接口、JWT認證受權接口。json

其中,博客後臺組中的接口須要受權後才能夠調用,須要受權那麼就涉及到身份驗證,在這裏準備採用JWT(JSON WEB TOKEN)的方式進行。api

分組

對Swagger進行分組很簡單,在.Swagger層中的擴展方法AddSwagger(this IServiceCollection services)中屢次調用options.SwaggerDoc(...)便可,像這樣app

...
    options.SwaggerDoc("v1", new OpenApiInfo
    {
        Version = "1.0.0",
        Title = "個人接口啊1",
        Description = "接口描述1"
    });
    options.SwaggerDoc("v2", new OpenApiInfo
    {
        Version = "1.0.0",
        Title = "個人接口啊2",
        Description = "接口描述2"
    });
    ...
...

不過這樣顯得有點low,而後能夠轉變一下思路使用遍歷的方式進行。options.SwaggerDoc(...)接收兩個參數:string name, OpenApiInfo infoui

name:能夠理解爲當前分組的前綴;OpenApiInfo:有許多可配置的參數,在這裏我只用到三個,VersionTitleDescriptionthis

要注意,當在AddSwagger(...)中調用完後,還須要在咱們的擴展方法UseSwaggerUI(this IApplicationBuilder app)options.SwaggerEndpoint()使用它,一樣的也用遍歷的方法。它接收的的參數:string url, string nameurl

url:這裏的url要與前面配置的name參數對應。spa

name:咱們自定義顯示的分組名稱。

因而能夠直接在擴展方法中新建一個內部類:SwaggerApiInfo

internal class SwaggerApiInfo
        {
            /// <summary>
            /// URL前綴
            /// </summary>
            public string UrlPrefix { get; set; }

            /// <summary>
            /// 名稱
            /// </summary>
            public string Name { get; set; }

            /// <summary>
            /// <see cref="Microsoft.OpenApi.Models.OpenApiInfo"/>
            /// </summary>
            public OpenApiInfo OpenApiInfo { get; set; }
        }

而後新建一個List<SwaggerApiInfo>手動爲其初始化一些值。

...
       /// <summary>
        /// Swagger分組信息,將進行遍歷使用
        /// </summary>
        private static readonly List<SwaggerApiInfo> ApiInfos = new List<SwaggerApiInfo>()
        {
            new SwaggerApiInfo
            {
                UrlPrefix = Grouping.GroupName_v1,
                Name = "博客前臺接口",
                OpenApiInfo = new OpenApiInfo
                {
                    Version = version,
                    Title = "阿星Plus - 博客前臺接口",
                    Description = description
                }
            },
            new SwaggerApiInfo
            {
                UrlPrefix = Grouping.GroupName_v2,
                Name = "博客後臺接口",
                OpenApiInfo = new OpenApiInfo
                {
                    Version = version,
                    Title = "阿星Plus - 博客後臺接口",
                    Description = description
                }
            },
            new SwaggerApiInfo
            {
                UrlPrefix = Grouping.GroupName_v3,
                Name = "通用公共接口",
                OpenApiInfo = new OpenApiInfo
                {
                    Version = version,
                    Title = "阿星Plus - 通用公共接口",
                    Description = description
                }
            },
            new SwaggerApiInfo
            {
                UrlPrefix = Grouping.GroupName_v4,
                Name = "JWT受權接口",
                OpenApiInfo = new OpenApiInfo
                {
                    Version = version,
                    Title = "阿星Plus - JWT受權接口",
                    Description = description
                }
            }
        };
...

version:咱們將其配置在appsettings.json中,作到動態能夠修改。

//AppSettings.cs
...
        /// <summary>
        /// ApiVersion
        /// </summary>
        public static string ApiVersion => _config["ApiVersion"];
...

//appsettings.json
{
...
  "ApiVersion": "1.0.0"
...
}

description:由於屢次使用,就定義一個變量,內容自擬主要是一些介紹性的描述,將在Swagger界面進行顯示。

UrlPrefix:分別爲,v1,v2,v3,v4。在Domain.Shared層中爲其定義好常量

//MeowvBlogConsts.cs
...
        /// <summary>
        /// 分組
        /// </summary>
        public static class Grouping
        {
            /// <summary>
            /// 博客前臺接口組
            /// </summary>
            public const string GroupName_v1 = "v1";

            /// <summary>
            /// 博客後臺接口組
            /// </summary>
            public const string GroupName_v2 = "v2";

            /// <summary>
            /// 其餘通用接口組
            /// </summary>
            public const string GroupName_v3 = "v3";

            /// <summary>
            /// JWT受權接口組
            /// </summary>
            public const string GroupName_v4 = "v4";
        }
...

如今修改擴展方法AddSwagger(...),遍歷List<SwaggerApiInfo>

...
        public static IServiceCollection AddSwagger(this IServiceCollection services)
        {
            return services.AddSwaggerGen(options =>
            {
                //options.SwaggerDoc("v1", new OpenApiInfo
                //{
                //    Version = "1.0.0",
                //    Title = "個人接口啊",
                //    Description = "接口描述"
                //});

                // 遍歷並應用Swagger分組信息
                ApiInfos.ForEach(x =>
                {
                    options.SwaggerDoc(x.UrlPrefix, x.OpenApiInfo);
                });
                ...
            });
        }
...

在擴展方法UseSwaggerUI(...)使用,通用也須要遍歷。

...
        // 遍歷分組信息,生成Json
        ApiInfos.ForEach(x =>
        {
                options.SwaggerEndpoint($"/swagger/{x.UrlPrefix}/swagger.json", x.Name);
        });
...

細心的同窗能夠發現,咱們前幾篇文章打開Swagger文檔的時候都是須要手動更改URL地址:.../swagger才能正確進入,其實Swagger是支持配置路由的。同時我們也將頁面Title也給改了吧。看下面UseSwaggerUI(...)完整代碼:

...
        /// <summary>
        /// UseSwaggerUI
        /// </summary>
        /// <param name="app"></param>
        public static void UseSwaggerUI(this IApplicationBuilder app)
        {
            app.UseSwaggerUI(options =>
            {
                // 遍歷分組信息,生成Json
                ApiInfos.ForEach(x =>
                {
                    options.SwaggerEndpoint($"/swagger/{x.UrlPrefix}/swagger.json", x.Name);
                });

                // 模型的默認擴展深度,設置爲 -1 徹底隱藏模型
                options.DefaultModelsExpandDepth(-1);
                // API文檔僅展開標記
                options.DocExpansion(DocExpansion.List);
                // API前綴設置爲空
                options.RoutePrefix = string.Empty;
                // API頁面Title
                options.DocumentTitle = "😍接口文檔 - 阿星Plus⭐⭐⭐";
            });
        }
...

options.DefaultModelsExpandDepth(-1);是模型的默認擴展深度,設置爲 -1 徹底隱藏模型。

options.DocExpansion(DocExpansion.List);表明API文檔僅展開標記,不默然展開全部接口,須要咱們手動去點擊才展開,能夠自行查看DocExpansion

options.RoutePrefix = string.Empty;表明路由設置爲空,直接打開頁面就能夠訪問了。

options.DocumentTitle = "😍接口文檔 - 阿星Plus⭐⭐⭐";是設置文檔頁面的標題的。

完成以上操做,在Controller中使用 Attribute:[ApiExplorerSettings(GroupName = ...)]指定是哪一個分組而後就能夠愉快的使用了。

默認不指定的話就是所有都有,目前只有兩個Controller,咱們將HelloWorldController設置成v3,BlogController設置成v1。

//HelloWorldController.cs
...
    [ApiExplorerSettings(GroupName = Grouping.GroupName_v3)]
    public class HelloWorldController : AbpController
    {
        ...
    }
...

//BlogController.cs
...
    [ApiExplorerSettings(GroupName = Grouping.GroupName_v1)]
    public class BlogController : AbpController
    {
        ...
    }
...

編譯運行,打開咱們的Swagger文檔看一下。

1

2

本身試着換切換一下分組試試吧,大功告成。​

描述

在Swagger文檔中,默認只顯示咱們的Controller的名稱,其實他也是支持描述信息的,這是就須要咱們自行擴展了。在.Swagger層新建一個文件夾Filters,添加SwaggerDocumentFilter類來實現IDocumentFilter接口。

//SwaggerDocumentFilter.cs
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Collections.Generic;
using System.Linq;

namespace Meowv.Blog.Swagger.Filters
{
    /// <summary>
    /// 對應Controller的API文檔描述信息
    /// </summary>
    public class SwaggerDocumentFilter : IDocumentFilter
    {
        public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
        {
            var tags = new List<OpenApiTag>
            {
                new OpenApiTag {
                    Name = "Blog",
                    Description = "我的博客相關接口",
                    ExternalDocs = new OpenApiExternalDocs { Description = "包含:文章/標籤/分類/友鏈" }
                }
                new OpenApiTag {
                    Name = "HelloWorld",
                    Description = "通用公共接口",
                    ExternalDocs = new OpenApiExternalDocs { Description = "這裏是一些通用的公共接口" }
                }
            };

            // 按照Name升序排序
            swaggerDoc.Tags = tags.OrderBy(x => x.Name).ToList();
        }
    }
}

實現Apply(...)方法後,使用Linq語法對文檔排個序,而後最重要的使用這個Filter,在擴展方法AddSwagger(...)中使用

public static IServiceCollection AddSwagger(this IServiceCollection services)
        {
            return services.AddSwaggerGen(options =>
            {
                ...
                // 應用Controller的API文檔描述信息
                options.DocumentFilter<SwaggerDocumentFilter>();
            });
        }

再打開Swagger文檔看看效果。

3

ok,此時描述信息也出來了。

小綠鎖

在Swagger文檔中開啓小綠鎖是很是簡單的,只需添加一個包:Swashbuckle.AspNetCore.Filters,直接使用命令安裝:Install-Package Swashbuckle.AspNetCore.Filters

而後再擴展方法AddSwagger(this IServiceCollection services)中調用

public static IServiceCollection AddSwagger(this IServiceCollection services)
{
    return services.AddSwaggerGen(options =>
    {
        ...
        var security = new OpenApiSecurityScheme
        {
            Description = "JWT模式受權,請輸入 Bearer {Token} 進行身份驗證",
            Name = "Authorization",
            In = ParameterLocation.Header,
            Type = SecuritySchemeType.ApiKey
        };
        options.AddSecurityDefinition("oauth2", security);
        options.AddSecurityRequirement(new OpenApiSecurityRequirement { { security, new List<string>() } });
        options.OperationFilter<AddResponseHeadersFilter>();
        options.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();
        options.OperationFilter<SecurityRequirementsOperationFilter>();
        ...
    });
}

以上便實現了在Swagger文檔中顯示小綠鎖,咱們new的OpenApiSecurityScheme對象,具體參數你們能夠自行看一下注釋就明白具體含義。分別調用options.AddSecurityDefinition(...)options.AddSecurityRequiremen(...)options.OperationFilter(...),編譯運行,打開瞅瞅。

4

如今只是作了小綠鎖的顯示,可是並無實際意義,由於在.net core中還須要配置咱們的身份認證受權代碼,才能具體發揮其真正的做用,因此目前咱們的api仍是處於裸奔狀態,誰都能調用你的api,等你發現你寫的文章都被別人刪了,你都不知道爲何。

實現JWT,將在下篇文章中詳細說明,本篇到這裏就結束了,咱們完善了Swagger文檔,給接口加了分組、描述,還有小綠鎖。老鐵,你學會了嗎?😁😁😁

開源地址:https://github.com/Meowv/Blog/tree/blog_tutorial

相關文章
相關標籤/搜索