Swashbuckle源码应用之最后一次修改Swagger中OpenApi.json机会
讲解Swashbuckle中对swagger的文档数据openapi.json的自定义配置。
一、场景
进行Asp.Net Web Api
还是 Asp.Net Core Web Api
项目后端服务开始时,引入Swagger
对应的UI
组件时,对于初学者来说,可能就是引入 Swashbuckle
或 NSwag
,代码添加如下:
此处以Vs2019
进行开发,使用.Net5
作为目标框架, 新建一个Asp.Net Core Web Api(空)
项目,Web
项目中添加依赖:
<Project Sdk="Microsoft.NET.Sdk.Web">
<!--添加Nuget依赖-->
<ItemGroup>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.1.1" />
</ItemGroup>
</Project>
Startup.cs
的服务配置函数 ConfigureServices
添加服务,同时设置 swagger
文档配置记录。
public void ConfigureServices(IServiceCollection services)
{
//注册服务Mvc核心服务,使用ApiExplorer
services.AddMvcCore().AddApiExplorer();
//注册SwaggerGen服务
services.AddSwaggerGen(options => {
//TODO: 添加文档openapi.json服务配置
options.SwaggerDoc("diy", new Microsoft.OpenApi.Models.OpenApiInfo { Version="diy",Title="自定义文档" });
});
}
在Configure
函数中配置中间件,具体内容如下:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// .........省略.......
// 1、 启用静态文件中间件
app.UseStaticFiles();
// 2、 启用swagger中间件
app.UseSwagger(options => {
// 2.1、配置自定义路由
options.RouteTemplate = "doc/{documentName}/swagger.json";
});
// 3、启用swagger-ui 中间件及配置
app.UseSwaggerUI(options => {
// 3.1、swagger-ui配置文档访问路由前缀
options.RoutePrefix = "doc";
// 3.2、配置swagger endpoint 对应访问openapi.json地址
options.SwaggerEndpoint("diy/swagger.json", "diy");
});
// swagger中间件引入在路由中间件之前
app.UseRouting();
app.UseEndpoints(endpoints =>
{
//模拟api
endpoints.MapGet("/api/diy", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
}
配置无误后,启动项目,访问http://localhost:5000/doc/index.html
,响应结果如下:
访问 http://localhost:5000/api/diy
,能够看到对应响应结果:
可以注意到,当前系项目中为空项目,并没有 Api
在文档中显示,如果希望将手动配置的 api
在文档中进行显示时,如果不通过新建对应controller
和action
,该如何去做?
app.UseEndpoints(endpoints =>
{
//模拟api
endpoints.MapGet("/api/diy", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
二、源码解析
没有思路的时候,先不急,先扒拉一下 Swashbuckle
对应源码,源码传送门,先看中间件 SwaggerMiddleware.cs
。
public class SwaggerMiddleware
{
private readonly RequestDelegate _next;
private readonly SwaggerOptions _options;
private readonly TemplateMatcher _requestMatcher;
public SwaggerMiddleware(
RequestDelegate next,
SwaggerOptions options)
{
// ...省略内容...
// 当构造注入的配置类为null时,内部进行实例化
_options = options ?? new SwaggerOptions();
// ...省略内容...
}
public async Task Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
{
// 判定请求的文档名称是否在已配置文档清单中...省略内容...
try
{
// .....省略内容.....
// 获取swagger类实例
var swagger = swaggerProvider.GetSwagger(
documentName: documentName,
host: null,
basePath: basePath);
// 在当前请求上下文中,最后一次修改 Swagger 文档的机会
foreach (var filter in _options.PreSerializeFilters)
{
filter(swagger, httpContext.Request);
}
// 判定响应的数据类型json或yaml.....内容省略.....
}
catch (UnknownSwaggerDocument)
{
RespondWithNotFound(httpContext.Response);
}
}
// ....省略内容....
}
上述代码中,可以注意到,有一组代码注释,非常友好,笔者由软件翻译的中文:
// 在当前请求上下文中,最后一次修改 Swagger 文档的机会
foreach (var filter in _options.PreSerializeFilters)
{
filter(swagger, httpContext.Request);
}
查看 Swashbuckle.AspNetCore.Swagger.SwaggerOptions 类,可以看出,PreSerializeFilters
是一个委托类型,公有读私有写的集合属性。
public class SwaggerOptions
{
public SwaggerOptions()
{
// 构造进行集合初始化
PreSerializeFilters = new List<Action<OpenApiDocument, HttpRequest>>();
SerializeAsV2 = false;
}
/// <summary>
/// Sets a custom route for the Swagger JSON/YAML endpoint(s). Must include the {documentName} parameter
/// </summary>
public string RouteTemplate { get; set; } = "swagger/{documentName}/swagger.{json|yaml}";
//....省略内容.....
/// <summary>
/// Actions that can be applied to an OpenApiDocument before it's serialized.
/// Useful for setting metadata that's derived from the current request
/// </summary>
public List<Action<OpenApiDocument, HttpRequest>> PreSerializeFilters { get; private set; }
}
查看中间件扩展函数类 Microsoft.AspNetCore.Builder.SwaggerBuilderExtensions.cs,其中,两个函数存在细微差别。
接受外部自定义 SwaggerOptions
实现自定义传入。
/// <summary>
/// Register the Swagger middleware with provided options
/// </summary>
public static IApplicationBuilder UseSwagger(this IApplicationBuilder app, SwaggerOptions options)
{
return app.UseMiddleware<SwaggerMiddleware>(options);
}
通过配置依赖方式实现中间件配置。
/// <summary>
/// Register the Swagger middleware with optional setup action for DI-injected options
/// </summary>
public static IApplicationBuilder UseSwagger(
this IApplicationBuilder app,
Action<SwaggerOptions> setupAction = null)
{
// 委托参数传入时,SwaggerOptions 由扩展函数内部进行实例化构造
SwaggerOptions options;
using (var scope = app.ApplicationServices.CreateScope())
{
// 进行实例化构造,与外部配置无关
options = scope.ServiceProvider.GetRequiredService<IOptionsSnapshot<SwaggerOptions>>().Value;
// 执行外部配置委托
setupAction?.Invoke(options);
}
return app.UseSwagger(options);
}
以上两个函数中,第一种是配置实例完全有用户使用时自定义实例和配置,第二种为方便函数的操作,添加的委托传入参数,该委托配置,在内部进行SwaggerOptions
实例化之后才执行。
三、自定义逻辑
通过添加自定义openapi.json
的生成内容,原有代码进行如下修改:
// 1、 启用静态文件中间件
app.UseStaticFiles();
// 2、 启用swagger中间件
SwaggerOptions options = new SwaggerOptions();
// 2.1、配置openapi.json访问路由
options.RouteTemplate = "doc/{documentName}/swagger.json";
// 2.2、添加自定义openapi.json结构
options.PreSerializeFilters.Add((swaggerDoc, httprequest) => {
//配置path
OpenApiPathItem path = new OpenApiPathItem
{
Description = "测试服务"
};
// 配置请求操作
OpenApiOperation operation = new OpenApiOperation();
operation.Tags.Add(new OpenApiTag { Name = "diy", Description = "自定义服务" });
operation.OperationId = "diy-get";
operation.Summary = "获取数据";
path.Operations.Add(OperationType.Get, operation);
// 设置操作tag
swaggerDoc.Tags.Add(new OpenApiTag { Name = "diy", Description = "自定义服务" });
// 添加path到文档中
swaggerDoc.Paths.Add("/api/diy", path);
});
app.UseSwagger(options);
// 3、启用swagger-ui 中间件及配置
// ...省略内容...
也可以传入委托参数:
// 1、 启用静态文件中间件
app.UseStaticFiles();
// 2、 启用swagger中间件
app.UseSwagger(options => {
// 2.1、配置openapi.json访问路由
options.RouteTemplate = "doc/{documentName}/swagger.json";
// 2.2、添加自定义openapi.json结构
options.PreSerializeFilters.Add((swaggerDoc, httprequest) =>
{
OpenApiPathItem path = new OpenApiPathItem
{
Description = "测试服务"
};
OpenApiOperation operation = new OpenApiOperation();
operation.Tags.Add(new OpenApiTag { Name = "diy", Description = "自定义服务" });
operation.OperationId = "diy-get";
operation.Summary = "获取数据";
path.Operations.Add(OperationType.Get, operation);
swaggerDoc.Tags.Add(new OpenApiTag { Name = "diy", Description = "自定义服务" });
swaggerDoc.Paths.Add("/api/diy", path);
});
});
// 3、启用swagger-ui 中间件及配置
// ...省略内容...
四、演示效果
确认无误后,运行项目,访问 http://localhost:5000/doc/index.html
,访问效果如下:
在线测试,效果如下:
以上就是本次对于自定义修改openapi.json
结果的基础教程。测试案例,可以添加笔者公众号
,联系作者进行获取。
更多推荐
所有评论(0)