SwaggerUI看烦了,IGeekFan.AspNetCore.Knife4jUI 帮你换个新皮肤

背景

好像是上周四,看到微信群有人说java有轮子swagger-bootstrap-ui,而c#,就是找不到。

于是我一看,就说大话:“这个只是一套UI,他这个有开源地址么”

被@at说:你试试...

当天晚上就把swagger-ui, Knife4j,Swashbuckle.AspNetCore项目的源码都下载下来研究下,看看能不能集成到AspNETCore下,这样我们就能给Swagger UI换套新皮肤。

knife4j

knife4j 是swagger-bootstrap-ui库的升级版,作者已全面升级,全部以knife4j命名。

Gitee上也有2.8K

  • 效果图

IGeekFan.AspNetCore.Knife4jUI

他是swagger ui 库:knife4j UI 的.NET Core封装,支持 .NET Core3.0+或.NET Standard2.0。

  • https://github.com/luoyunchong/IGeekFan.AspNetCore.Knife4jUI

概念对应关系如下

功能c#java
实现swagger规范Swashbuckle.AspNetCorespring-fox
封装成nuget包/maven包的UI库Swashbuckle.AspNetCore.SwaggerUIknife4j-v3-spring-ui
UI库swagger-ui-distknife4j-vue-v3(swagger v3版本)

注意

swagger v2和v3版本不一样,我只实现了swagger v3版本的封装。

源码下载

  • https://gitee.com/xiaoym/knife4j

  • https://github.com/domaindrivendev/Swashbuckle.AspNetCore

Swashbuckle.AspNetCore.SwaggerUI源码分析。

通过中间件SwaggerUI中间件Middleware,Invoke方法中,替换了Index.html中的%(DocumentTitle) %(HeadContent),%(ConfigObject)等等 。

private readonly SwaggerUIOptions _options;
//xxxpublic async Task Invoke(HttpContext httpContext)
{ 
//xxxif (httpMethod == "GET" && Regex.IsMatch(path, $"^/{Regex.Escape(_options.RoutePrefix)}/?index.html$")){await RespondWithIndexHtml(httpContext.Response);return;}
//xxx}private async Task RespondWithIndexHtml(HttpResponse response)
{response.StatusCode = 200;response.ContentType = "text/html;charset=utf-8";using (var stream = _options.IndexStream()){// Inject arguments before writing to responsevar htmlBuilder = new StringBuilder(new StreamReader(stream).ReadToEnd());foreach (var entry in GetIndexArguments()){htmlBuilder.Replace(entry.Key, entry.Value);}await response.WriteAsync(htmlBuilder.ToString(), Encoding.UTF8);}
}private IDictionary<string, string> GetIndexArguments()
{return new Dictionary<string, string>(){{ "%(DocumentTitle)", _options.DocumentTitle },{ "%(HeadContent)", _options.HeadContent },{ "%(ConfigObject)", JsonSerializer.Serialize(_options.ConfigObject, _jsonSerializerOptions) },{ "%(OAuthConfigObject)", JsonSerializer.Serialize(_options.OAuthConfigObject, _jsonSerializerOptions) }};
}

在index.html中。

<title>%(DocumentTitle)</title>
var configObject = JSON.parse('%(ConfigObject)');
var oauthConfigObject = JSON.parse('%(OAuthConfigObject)');

当我们写的aspnetcore项目集成swagger组件后,只会有一个ajax的异步请求

knife4j-v3-spring-ui

效果(2.X版):http://knife4j.xiaominfo.com/doc.html

由于官方也没有v3的demo,我们可以暂时通过v2分析,发现他有3个异步请求,有一个请求返回相似的。另一个则是swagger的配置项,可以发现,返回值与SwaggerUIOptions一致。

功能c# (swagger v3)java(swagger v2)
获取分组配置/swagger-resources
swagger配置项/swagger-resources/configuration/ui
api文档https://api.igeekfan.cn/swagger/v1/swagger.json/v2/api-docs?group=2.X版本

结构如下。

  • 版本分组配置

  • http://knife4j.xiaominfo.com/swagger-resources

[{"name":"2.X版本","url":"/v2/api-docs?group=2.X版本","swaggerVersion":"2.0","location":"/v2/api-docs?group=2.X版本"},{"name":"分组接口","url":"/v2/api-docs?group=分组接口","swaggerVersion":"2.0","location":"/v2/api-docs?group=分组接口"},{"name":"默认接口","url":"/v2/api-docs?group=默认接口","swaggerVersion":"2.0","location":"/v2/api-docs?group=默认接口"}
]
  • swagger 配置项

  • http://knife4j.xiaominfo.com/swagger-resources/configuration/ui 请求方法: GET

{"deepLinking":true,"displayOperationId":false,"defaultModelsExpandDepth":1,"defaultModelExpandDepth":1,"defaultModelRendering":"example","displayRequestDuration":false,"docExpansion":"none","filter":false,"operationsSorter":"alpha","showExtensions":false,"tagsSorter":"alpha","validatorUrl":"","apisSorter":"alpha","jsonEditor":false,"showRequestHeaders":false,"supportedSubmitMethods":["get","put","post","delete","options","head","patch","trace"]
}
  • api 文档

  • http://knife4j.xiaominfo.com/v2/api-docs?group=2.X%E7%89%88%E6%9C%AC

接下来我们看下knife4j,可以看到,他有knife4j-vue-v3项目,这个是swagger v3版本的vue实现。

我们打开knife4j-vue-v3项目,修改配置项vue.config.js,devServer 反向代理的地址(后台地址)

proxy: {"/": {target: 'http://localhost:5000/',ws: true,changeOrigin: true}
}

安装依赖,并运行他

yarn install
yarn serve

我们会看到一个请求错误。Knife4j文档请求异常,因为后台并没有:'/v3/api-docs/swagger-config'。

也就是上文中的/swagger-resources/configuration/ui,我们可以在SwaggerUIMiddleware中间件获取这些参数,原本是通过替换字符串,现在,我们可以写一个api。怎么写呢。

下载Swashbuckle.AspNetCore的源码,打开Swashbuckle.AspNetCore.sln。

我们尝试修改Swashbuckle.AspNetCore.SwaggerUI项目中,SwaggerUIMiddleware中的源码。

Invoke方法增加如下处理,将配置项直接返回json串。

if (httpMethod == "GET" && Regex.IsMatch(path, $"^/v3/api-docs/swagger-config$"))
{await httpContext.Response.WriteAsync(JsonSerializer.Serialize(_options.ConfigObject, _jsonSerializerOptions));return;
}

在swagger v3 版本中,/v3/api-docs/swagger-config,返回了分组信息,urls字段。

效果如下

image

设置test/WebSites/Basic项目为启动项目,运行后,打开了http://localhost:5000/index.html,这个还是原本的swagger ui,我们打开http://localhost:8080/#/home,前台依旧提示有问题。

AddSwaggerGen 需要增加Server,前台判断有BUG,非空。

image

servers.length得到的是0,问号表达式就会执行后面的servers[0].url,

临时方案

services.AddSwaggerGen(c =>
{c.AddServer(new OpenApiServer(){Url = "",Description = "v1"});
});

但还有一个问题,前台根据operationId生成的路由,    [HttpPost(Name = "CreateProduct")]比如CreateProduct。有些没有设置 Name的,点击后就会出现空白界面。

增加CustomOperationIds的配置,通过反射获取方法名。

services.AddSwaggerGen(c =>
{//xxc.CustomOperationIds(apiDesc =>{return apiDesc.TryGetMethodInfo(out MethodInfo methodInfo) ? methodInfo.Name : null;});
});

解决了这些问题。

我们创建一个新类库,起名IGeekFan.AspNetCore.Knife4jUI

将前端打包。修改打包文件配置,vue.config.js

assetsDir: "knife4j",
indexPath: "index.html"

打包

yarn run build

复制到根目录,设置为嵌入文件,删除不需要的images和txt文本。

<ItemGroup><EmbeddedResource Include="knife4j/**/*" /><EmbeddedResource Include="favicon.ico" /><EmbeddedResource Include="index.html" />
</ItemGroup>

将后台Swashbuckle.AspNetCore.SwaggerUI的代码复制过来,全部重命名。比如中间件名字为

SwaggerUIMiddleware -> Knife4jUIMiddleware。即SwaggerUI都改成Knife4jUI。

Knife4jUIMiddleware修改位置

private const string EmbeddedFileNamespace = "IGeekFan.AspNetCore.Knife4jUI";

删除无用的替换变量,增加

Knife4UIOptions 修改

public Func<Stream> IndexStream { get; set; } = () => typeof(Knife4UIOptions).GetTypeInfo().Assembly.GetManifestResourceStream("IGeekFan.AspNetCore.Knife4jUI.index.html");

Startup 中的Configure中间件

将UseSwaggerUI()改成UseKnife4UI()

app.UseKnife4UI(c =>
{c.RoutePrefix = ""; // serve the UI at rootc.SwaggerEndpoint("/v1/api-docs", "V1 Docs");c.SwaggerEndpoint("/gp/api-docs", "登录模块");
});

不用IGeekFan.AspNetCore.Knife4jUI也能实现?

当然,可以。

我们也能通过其他方式,在SwaggerUI的基础上,替换比如替换Index.html页面,自己打包前端UI,复制到项目中等。

将knife4j-vue-v3项目打包,放到wwwwroot目录中。

需要配置静态文件。

    app.UseStaticFiles();
app.UseSwaggerUI(c =>
{c.RoutePrefix = ""; // serve the UI at rootc.SwaggerEndpoint("/v1/api-docs", "V1 Docs");//这个配置无效。c.IndexStream = () => new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot")).GetFileInfo("index.html").CreateReadStream();
});

重写/v3/api-docs/swagger-config路由

app.UseEndpoints(endpoints =>
{endpoints.MapControllers();endpoints.MapSwagger("{documentName}/api-docs");endpoints.MapGet("/v3/api-docs/swagger-config", async (httpContext) =>{JsonSerializerOptions _jsonSerializerOptions = new JsonSerializerOptions();_jsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;_jsonSerializerOptions.IgnoreNullValues = true;_jsonSerializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase, false));SwaggerUIOptions _options = new SwaggerUIOptions(){ConfigObject = new ConfigObject(){Urls = new List<UrlDescriptor>{new UrlDescriptor(){Url="/v1/api-docs",Name="V1 Docs"}}}};await httpContext.Response.WriteAsync(JsonSerializer.Serialize(_options.ConfigObject, _jsonSerializerOptions));});
});

IGeekFan.AspNetCore.Knife4jUI指南

相关依赖项

knife4j

  • knife4j-vue-v3(不是vue3,而是swagger-ui-v3版本)

Swashbuckle.AspNetCore

  • Swashbuckle.AspNetCore.Swagger

  • Swashbuckle.AspNetCore.SwaggerGen

Demo

  • Basic

  • Knife4jUIDemo

???? 快速开始

????安装包

1.Install the standard Nuget package into your ASP.NET Core application.

Package Manager : Install-Package IGeekFan.AspNetCore.Knife4jUI
CLI : dotnet add package IGeekFan.AspNetCore.Knife4jUI

2.In the ConfigureServices method of Startup.cs, register the Swagger generator, defining one or more Swagger documents.

using System.Reflection;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using IGeekFan.AspNetCore.Knife4jUI;

???? ConfigureServices

3.服务配置,CustomOperationIds和AddServer是必须的。

   services.AddSwaggerGen(c =>{c.SwaggerDoc("v1",new OpenApiInfo{Title = "API V1",Version = "v1"});c.AddServer(new OpenApiServer(){Url = "",Description = "vvv"});c.CustomOperationIds(apiDesc =>{return apiDesc.TryGetMethodInfo(out MethodInfo methodInfo) ? methodInfo.Name : null;});});

???? Configure

  1. 中间件配置

app.UseSwagger();app.UseKnife4UI(c =>
{c.RoutePrefix = ""; // serve the UI at rootc.SwaggerEndpoint("/v1/api-docs", "V1 Docs");
});app.UseEndpoints(endpoints =>
{endpoints.MapControllers();endpoints.MapSwagger("{documentName}/api-docs");
});

???? 效果图

运行项目,打开 https://localhost:5001/index.html#/home

https://pic.downk.cc/item/5f2fa77b14195aa594ccbedc.jpg

更多配置请参考

  • https://github.com/domaindrivendev/Swashbuckle.AspNetCore

更多项目

  • https://api.igeekfan.cn/swagger/index.html

  • https://github.com/luoyunchong/lin-cms-dotnetcore

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/308340.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

7-48 银行排队问题之单窗口“夹塞”版 (30 分)(思路和详解+map做法)来呀Baby!

一&#xff1a;题目 排队“夹塞”是引起大家强烈不满的行为&#xff0c;但是这种现象时常存在。在银行的单窗口排队问题中&#xff0c;假设银行只有1个窗口提供服务&#xff0c;所有顾客按到达时间排成一条长龙。当窗口空闲时&#xff0c;下一位顾客即去该窗口处理事务。此时如…

7-49 打印学生选课清单 (25 分)(思路+详解+map做法(一对多)+超时解决)Come baby!

一&#xff1a;题目 假设全校有最多40000名学生和最多2500门课程。现给出每门课的选课学生名单&#xff0c;要求输出每个前来查询的学生的选课清单。 输入格式: 输入的第一行是两个正整数&#xff1a;N&#xff08;≤40000&#xff09;&#xff0c;为前来查询课表的学生总数&…

记一次批量处理数据库中的敏感信息

前言 对于一些敏感数据&#xff0c;往往会对其加密后再入库&#xff0c;这个是对数据安全性的一个最为简单的措施。最常见的莫过于手机号码和身份证号了&#xff0c;相信还是有不少公司对这些敏感信息是明文存储的。万一被别人发现系统漏洞&#xff0c;或者是被拖库&#xff0c…

7-50 畅通工程之局部最小花费问题 (35 分)(思路加详解)来呀兄弟们冲呀呀呀呀呀呀呀

一&#xff1a;题目 某地区经过对城镇交通状况的调查&#xff0c;得到现有城镇间快速道路的统计数据&#xff0c;并提出“畅通工程”的目标&#xff1a;使整个地区任何两个城镇间都可以实现快速交通&#xff08;但不一定有直接的快速道路相连&#xff0c;只要互相间接通过快速…

十多位全球技术专家,为你献上近十个小时的.Net微服务介绍

.Net Conf: Focus on Microservices 是 .Net Conf 社区在 2020 年 7 月 30 日举办的线上分享活动。整个活动视频长达近 10 个小时。今天我们来看看都发生了什么。章节汇总本次分享由十多位来自全球的资深技术专家在线分享&#xff0c;涵盖了当前 .Net 在微服务领域的利器。包括…

5G发展是绵绵秋雨 应循序渐进

现阶段5G技术成熟度有待提升当下&#xff0c;在行业内5G基站的短板被调侃为“覆盖、成本、功耗三个3”&#xff0c;也就是3倍成本&#xff0c;3倍功耗、1/3覆盖。就功耗来说&#xff0c;5G基站是4G基站功耗的3倍左右。中国移动董事长杨杰就在GTI国际产业峰会表示&#xff0c;“…

7-52 两个有序链表序列的交集 (20 分)(思路加详解尾插法)come Boby!

一&#xff1a;题目 已知两个非降序链表序列S1与S2&#xff0c;设计函数构造出S1与S2的交集新链表S3。 输入格式: 输入分两行&#xff0c;分别在每行给出由若干个正整数构成的非降序序列&#xff0c;用−1表示序列的结尾&#xff08;−1不属于这个序列&#xff09;。数字用空…

明源云创CI/CD技术演进

源宝导读&#xff1a;在敏捷迭代的过程中需要能够快速的把开发的代码集成打包部署到各个环节对应的环境中。为了高效稳定的完成这个工作&#xff0c;我们引入了DevOps实践理论&#xff0c;并形成了配套的CI/CD工具。本文将介绍云创的CI/CD工具如何演进的过程。一 、传统构建在最…

7-51 两个有序链表序列的合并 (20 分)(vector做法)

一 &#xff1a;题目 、已知两个非降序链表序列S1与S2&#xff0c;设计函数构造出S1与S2合并后的新的非降序链表S3。 输入格式: 输入分两行&#xff0c;分别在每行给出由若干个正整数构成的非降序序列&#xff0c;用−1表示序列的结尾&#xff08;−1不属于这个序列&#xff…

linux qt4卸载,linux卸载QT4和安装QT5的方法

由于项目中需要用到QT的程序&#xff0c;因此安装QT5的软件支持库和QT开发环境是必须的&#xff1a;apt-get insatall qt5-defaultapt-get insatall qt-creatorQT5的库和QT Creator开发环境是独立运行的&#xff0c;如果QT Creator缺少QT5的库则程序写好了没法编译&#xff1b;…

7-53 两个有序序列的中位数 (25 分)(思路加详解)用STL容器中的set容器的自动去重过不去

一&#xff1a;题目 已知有两个等长的非降序序列S1, S2, 设计函数求S1与S2并集的中位数。有序序列A 0 ​ ,A 1 ​ ,⋯,A N−1 ​ 的中位数指A (N−1)/2 ​ 的值,即第⌊(N1)/2⌋个数&#xff08;A 0 ​ 为第1个数&#xff09;。 输入格式: 输入分三行。第一行给出序列的公共长…

Blazor带我重玩前端(五)

概述本文主要讨论Blazor事件内容&#xff0c;由于blazor事件部分很多&#xff0c;所以会分成上下两篇&#xff0c;本文为第一篇&#xff0c;后续会有第二篇。我们可以视组件是一个类&#xff0c;我们先看一下前文所说的Index.Razor页面生成的C#代码。在此&#xff0c;先补充一下…

关于TensorFlow开发者证书,你想要的资源都在这里!

今天是TensorFlow开发者证书的一个里程碑&#xff0c;全球已经有500位开发者通过考试并顺利拿到了 TensorFlow Certificate。我也有幸在各位大佬的指点下&#xff0c;顺利通过考试&#xff0c;成为国内第7位拿到 TensorFlow Certificate 的开发者。按照Google官网的数据&#…

Kubernetes 在知名互联网公司的(dotnet)落地实践

容器化背景本来生活网&#xff08;benlai.com&#xff09;是一家生鲜电商平台&#xff0c;公司很早就停止了烧钱模式&#xff0c;开始追求盈利。既然要把利润最大化&#xff0c;那就要开源节流&#xff0c;作为技术可以在省钱的方面想想办法。我们的生产环境是由 IDC 机房的 10…

Java银行开户,取钱,存钱,查询余额,退出。。。。。

一&#xff1a;上码 package com.wyj.two;import java.util.Scanner;/*** 封装的练习*/ public class Demo8 {public static void main(String[] args) {Scanner in new Scanner(System.in);Account account new Account();System.out.println("欢迎来到杰哥银行"…

linux开发亿连手机互联,亿连手机互联车载版下载-亿连手机互联车机版v6.6.1 安卓版-腾牛安卓网...

亿连手机互联车机版&#xff0c;交互一体&#xff0c;手机-导航仪应用深度融合&#xff1b;升级服务&#xff0c;依托手机OTA升级导航仪应用&#xff1b;流畅连接&#xff0c;双通道互联技术连接更流畅&#xff1b;全新界面&#xff0c;配合前装和后装专业市场&#xff1b;为您…

7-3 树的同构 (25 分)(思路加详解)来呀baby!!!!!!!!

一&#xff1a;题目 7-3 树的同构 (25 分) 给定两棵树T1和T2。如果T1可以通过若干次左右孩子互换就变成T2&#xff0c;则我们称两棵树是“同构”的。例如图1给出的两棵树就是同构的&#xff0c;因为我们把其中一棵树的结点A、B、G的左右孩子互换后&#xff0c;就得到另外一棵树…

Dapr微服务应用开发系列0:概述

题记&#xff1a;Dapr是什么&#xff0c;Dapr包含什么&#xff0c;为什么要用Dapr。Dapr是什么Dapr&#xff08;Distributed Application Runtime&#xff09;&#xff0c;是微软Azure内部创新孵化团队的一个开源项目&#xff0c;皆在解决微服务应用开发过程的一些共性问题。以…

你以为.NET Core仅仅是开源跨平台?试试Docker,刷新你的认知!

2016 年微软发布了 .NET Core 1.0&#xff0c;可谓是平地起惊雷&#xff0c;因为微软终于开源和跨平台了。但是一直到19年12月份发布了.NET Core3.1&#xff0c;开源社区的威力才展现出来&#xff0c;3个月增加了100w开发者&#xff0c;才真正吸引大厂的关注。但你以为仅仅是因…

7-2 一元多项式的乘法与加法运算 (20 分)(思路加详解+map做法)map真香啊 各个测试点的用例子 来吧宝贝!

一&#xff1a;题目 设计函数分别求两个一元多项式的乘积与和。 输入格式: 输入分2行&#xff0c;每行分别先给出多项式非零项的个数&#xff0c;再以指数递降方式输入一个多项式非零项系数和指数&#xff08;绝对值均为不超过1000的整数&#xff09;。数字间以空格分隔。 输…