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 版本
在 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 。
在之前添加的类库 “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 被设为了默认值 “张三”。