一、场景
进行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
结果的基础教程。测试案例,可以添加笔者公众号
,联系作者进行获取。