|
主题设置

卡片式面板通常用于非白色背景色的主体内

Swagger 配置

Swagger 提供了一种标准的方式来描述 API 的结构、参数、响应以及与 API 交互的方法,使得开发者可以更容易地理解和使用 API。通过使用 Swagger,开发者可以通过浏览器轻松地浏览和测试 API 端点。

注释展示

在 Program.cs 类中引用 Swagger

下图 2 个红框中的内容,即是对 Swagger 的引用。

引用完 Swagger 后,对控制器中的方法增加注释,这里对上一页中创建的 FirstController 中的方法添加如下注释。

增加完注释后直接启动项目,发现 Swagger 中并不会显示注释。

这是因为需要进行一些配置,才能在 Swagger 中显示注释。

右键当前项目——属性

在 “生成” 中勾选 “文档文件”

在项目上右键,重新生成项目。

重新生成后,在项目上 “右键——在文件资源管理器中打开文件夹”

在打开的文件夹中,发现在 bin——Debug——net6.0 / 8.0 中生成了一个 webapi_rumen.xml 的文件

打开 webapi_rumen.xml 文件看一下,发现其中保存的就是 FirstController 控制器中方法的注释。

那接下来就需要把这个文件引用起来

打开 Program.cs 文件,修改 builder.Services.AddSwaggerGen(); 语句如下:

builder.Services.AddSwaggerGen(option =>
{
    #region Swagger的注释的展示
    {
        // 获取应用程序所在目录(项目文件夹下的 bin\Debug\net6.0\ 中的 exe 文件所在目录)
        string basePath = AppContext.BaseDirectory;
        // 拼接上目录中保存注释的文件 webapi_rumen.xml 的文件名
        string xmlPath = Path.Combine(basePath, "webapi_rumen.xml");
        // 加载保存注释的文件
        option.IncludeXmlComments(xmlPath);
    }
    #endregion
});

启动项目注释展示成功

版本控制

如果控制器有多个版本,比如 FirstController 不想用了,新建了 FirstV2Controller 控制器,就需要用到版本控制。

新建了 FirstV2Controller 控制器后,启动项目,发现 Swagger 里面会同时展示 FirstController 和 FirstV2Controller。

接下来利用 Swagger 做一下版本筛选,过滤掉 FirstController。

为了后面的可扩展性,在解决方案上 “右键——添加——新建项目” 。

在弹出的 “添加新项目” 窗体中,筛选 “类库”,选择 C# 的类库,然后点击 “下一步”。

学习到后面,我感觉没必要单独新建类库,或许是我学习的不够深入。

指定类库名称,然后点击下一步。

创建

创建成功

将 webapi_rumen_class_lib 中的 Class1 重命名为 ApiVersionInfo,同时修改为静态类,并添加内容。

完成后打开 Program.cs 文件,在 builder.Services.AddSwaggerGen 中增加 Swagger 的版本控制。

#region Swagger的版本控制
{
    // 获取到所有的版本并遍历
    foreach (FieldInfo field in typeof(ApiVersionInfo).GetFields())
    {
        // 配置 Swagger 的 Doc 文档
        option.SwaggerDoc(field.Name, new OpenApiInfo()
        {
            // 指定版本
            Title = $"{field.Name}:这里是 webapi 学习",
            Version = field.Name,
            Description = $"webapi {field.Name} 版本" // 描述
        });
    }
}
#endregion

Program.cs 文件中还有一处要修改,在 UseSwaggerUI 时,增加相应配置。

app.UseSwaggerUI(option =>
{
    // 获取到所有的版本并遍历
    foreach (FieldInfo field in typeof(ApiVersionInfo).GetFields())
    {
        // 指定版本,每个版本会生成一个 json 文件
        option.SwaggerEndpoint($"/swagger/{field.Name}/swagger.json",$"{field.Name}");
    }
});

对控制器进行版本划分

打开 FirstController 控制器,指定版本,用以下代码将其指定为 V1 版本。

[ApiExplorerSettings(GroupName = nameof(ApiVersionInfo.V1))]

打开 FirstV2Controller 控制器,指定版本,用以下代码将其指定为 V2 版本。

[ApiExplorerSettings(GroupName = nameof(ApiVersionInfo.V2))]

到此版本控制设置完成,启动项目。

接下来,点击下拉框切换到 V1 版本。

切换到 V2 版本

Token 传递

在 Program.cs 文件中的 builder.Services.AddSwaggerGen 中增加对 Token 的设置。

#region Swagger的token传递
{
    option.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
    {
        Description = "请输入 Token,格式为 Bearer xxxxxxx(注意中间必须有空格)", // 描述
        Name = "Authorization", // 名字
        In = ParameterLocation.Header, // 指定将 Token 放到 HTTP 请求的头信息里面进行传递
        Type = SecuritySchemeType.ApiKey, // 类型是 ApiKey
        BearerFormat = "JWT", // "JWT" 代表 JSON Web Token,这是一种用于安全传输信息的开放标准
        Scheme = "Bearer" // 表示 API 要求客户端在发送请求时使用 Bearer 认证方案,即将访问令牌作为身份验证凭据的一部分,并在请求头部中使用 Authorization 字段来传递这个令牌。
    });

    // 添加安全要求
    option.AddSecurityRequirement(new OpenApiSecurityRequirement
    {
        {
            new OpenApiSecurityScheme
            {
                Reference = new OpenApiReference()
                {
                    Type = ReferenceType.SecurityScheme,
                    Id = "Bearer"
                }
            },
            new string[]{}
        }
    });
}
#endregion

添加完成后启动项目,发现 Swagger 页面的右上角多了一个 “Authorize” 的按钮。

点击 “Authorize” 按钮,会弹出要求输入 Token 的弹窗。输入后再点击输入框下方的 “Authorize” 按钮。

接下来测试一下 Token 的传递

在 Swagger 页面中,通过 “Try it out——Execute” 调用一个 API 接口,可以在浏览器的网络(Network)中看到传递的 Token 。

Swagger 的封装

在之前添加的类库 “webapi_rumen_class_lib” 中,新建一个 Swagger 的扩展文件夹 SwaggerExtend(名称最好改为 Extensions,后续其他功能的封装也可以放进去)。

在 SwaggerExtend 文件夹中添加一个类 SwaggerExtension.cs

编辑 SwaggerExtension.cs 类

public class SwaggerExtension
{
	// 因为在 Program.cs 中,Swagger 是在 builder.Services 中进行配置的,所以以下方法中也需要定义 IServiceCollection的service
	public static void AddSwaggerExt(IServiceCollection service)
	{
		// 直接把 Program.cs 中对 Swagger 的配置复制过来,将其中的 builder.Services 替换为 service
		service.AddEndpointsApiExplorer();
		service.AddSwaggerGen(option =>
		{
			#region Swagger 的注释的展示
			{
				// 获取应用程序所在目录(项目文件夹下的 bin\Debug\net6.0\ 中的 exe 文件所在目录)
				string basePath = AppContext.BaseDirectory;
				// 拼接上目录中保存注释的文件 webapi_rumen.xml 的文件名
				string xmlPath = Path.Combine(basePath, "webapi_rumen.xml");
				// 加载保存注释的文件
				option.IncludeXmlComments(xmlPath);
			}
			#endregion 

			#region Swagger 的版本控制
			{
				// 获取到所有的版本并遍历
				foreach (FieldInfo field in typeof(ApiVersionInfo).GetFields())
				{
					// 配置 Swagger 的 Doc 文档
					option.SwaggerDoc(field.Name, new OpenApiInfo()
					{
						// 指定版本
						Title = $"{field.Name}:这里是 webapi 学习",
						Version = field.Name,
						Description = $"webapi {field.Name} 版本" // 描述
					});
				}
			}
			#endregion

			#region Swagger 的 token 传递
			{
				option.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
				{
					Description = "请输入 Token,格式为 Bearer xxxxxxx(注意中间必须有空格)", // 描述
					Name = "Authorization", // 名字
					In = ParameterLocation.Header, // 指定将 Token 放到 HTTP 请求的头信息里面进行传递
					Type = SecuritySchemeType.ApiKey, // 类型是 ApiKey
					BearerFormat = "JWT", // "JWT" 代表 JSON Web Token,这是一种用于安全传输信息的开放标准
					Scheme = "Bearer" // 表示 API 要求客户端在发送请求时使用 Bearer 认证方案,即将访问令牌作为身份验证凭据的一部分,并在请求头部中使用 Authorization 字段来传递这个令牌。
				});

				// 添加安全要求
				option.AddSecurityRequirement(new OpenApiSecurityRequirement
				{
					{
						new OpenApiSecurityScheme
						{
							Reference = new OpenApiReference()
							{
								Type = ReferenceType.SecurityScheme,
								Id = "Bearer"
							}
						},
						new string[]{}
					}
				});
			}
			#endregion
		});
	}
}

发现有 2 处报错,需要安装依赖项。

先看下之前在 Program.cs 中配置 Swagger 时,这两处的依赖项是什么:Swashbuckle.AspNetCore(6.5.0)

那么在类库 webapi_rumen_class_lib 的依赖项中也安装这个依赖。

Program.cs 中安装的版本是 6.5.0,这里也必须安装 6.5.0,版本必须一致。

在 webapi_rumen_class_lib 的依赖项上 “右键——管理 NuGet 程序包(N)”,在 “浏览” 中搜索:Swashbuckle.AspNetCore,安装时注意版本。

安装完成后,发现 SwaggerExtension 中原有的 2 处报错就解决了。

但是下面对 Swagger 的配置中,产生了一些报错。

对报错内容引入命名空间进行解决,引入后报错消失。

至此 Swagger 的初步封装完成。

需要在 Program.cs 中把之前对 Swagger 的配置注释掉,然后引入 Swagger 的封装方法。

因为 Program.cs 中的 if (app.Environment.IsDevelopment()) 处还有对 Swagger 的配置,所以继续封装。

在 SwaggerExtension 类中增加 UseSwaggerExt 方法,方法内容直接复制的 Program.cs 中的的配置内容,如下:

public static void UseSwaggerExt(WebApplication app)
{
    app.UseSwagger();
    app.UseSwaggerUI(option =>
    {
        // 获取到所有的版本并遍历
        foreach (FieldInfo field in typeof(ApiVersionInfo).GetFields())
        {
            // 指定版本,每个版本会生成一个 json 文件
            option.SwaggerEndpoint($"/swagger/{field.Name}/swagger.json", $"{field.Name}");
        }
    });
}

封装完成

然后注释掉 Program.cs 中此处对 Swagger 的配置,然后引入 Swagger 的封装方法。

为了进一步封装,将版本控制的 ApiVersionInfo.cs 类也调整到 SwaggerExtend 文件夹中。

重新生成解决方案,查看是否有报错。

没有报错的话,启动项目。

启动成功

到此为止虽然成功封装了 Swagger,但是 Program.cs 中的代码看起来不统一、不美观。

继续修改 SwaggerExtenSion.cs 类

将 SwaggerExtenSion.cs 改成静态类,并且对 AddSwaggerExt 和 UseSwaggerExt 中的方法使用 this 修饰。

this 修饰静态类中的静态方法时,会将方法变为扩展方法,可以通过传入的参数直接进行调用。

修改 Program.cs 类中的封装引用,通过传入的参数直接调用 Swagge 封装中的扩展方法。

封装完成。

设置参数默认值

通过类型设置

在 Swagger 中通过 “Try it out” 调用 API 时,如果传入或返回的参数没有被赋值,那么参数值会变成参数的类型。(如果是实例对象,那没有被赋值的属性,属性值会变成属性的类型)

只有在 Swagger 中通过 “Try it out” 调用时,才会出现这个问题。如果自己写程序调用,或者使用 postman 调用,则不会有这个问题。

为了解决这个问题,即在返回对象的属性没有被赋值时,不显示属性类型,需要以下操作。

先 Swagger 的类库中创建一个 FilterConfig 的文件夹,在文件夹中创建 DefaultValueSchemaFilter.cs 的类。

DefaultValueSchemaFilter.cs 类的内容如下:

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

namespace webapi_rumen.FilterConfig
{
    public class DefaultValueSchemaFilter : ISchemaFilter
    {
        public void Apply(OpenApiSchema schema,SchemaFilterContext context)
        {
            if(schema == null)
            {
                return;
            }
            var objectSchema = schema;
            foreach(var property in objectSchema.Properties)
            {
				// 方法一:根据属性类型设置默认值
                if(property.Value.Type == "string" && property.Value.Default == null)
                {
                    property.Value.Default = new OpenApiString("");
                }
            }
        }
    }
}

在 SwaggerExtension.cs 中引用这个过滤器:

#region 参数引用过滤器,设置对象实例的默认值
option.SchemaFilter<DefaultValueSchemaFilter>();
#endregion

启动项目,查看参数的默认值是否设置成功。

从下图中可以看到设置已经成功了。

通过属性名设置

在 DefaultValueSchemaFilter.cs 中增加 “根据属性名设置默认值” 的内容。

// 方法二:根据属性名设置默认值
if(property.Key == "name")
{
    property.Value.Default = new OpenApiString("李四");
}
else if(property.Key == "address")
{
    property.Value.Default = new OpenApiString("中国");
}

增加完后启动项目,默认值已经设置完成。

通过特性设置默认值

首先在 Users 类上面增加设置:[DefaultValue("张三")]

然后在 DefaultValueSchemaFilter.cs 中进行设置

// 方法三:通过特性设置默认值
DefaultValueAttribute defaultValueAttribute = context.ParameterInfo?.GetCustomAttribute();
if (defaultValueAttribute != null)
{
    property.Value.Example = (IOpenApiAny)defaultValueAttribute.Value;
}

启动项目,id 被设为了默认值 “张三”。