标签 Swagger 下的文章 - 一叶舟轻
首页
友链
关于
搜 索
1
解决Typecho不能加载css和js的问题
36 阅读
2
zeroiter+nginx 内网穿透
35 阅读
3
blazor 自动热加载 动态调试方法
30 阅读
4
hyper-v中的虚拟机Ubuntu Server磁盘扩容
26 阅读
5
.Net6项目发布出错(检测到包降级: System.xxxx 从 x.x.x 降级到 x.x.x。直接从项目引用包以选择不同版本。)
25 阅读
《也许你也想建站?》
《代码的海洋》
《生活日常》
《技能get》
登录
搜 索
标签搜索
.NET
Docker
Linux
VisualStudio
Blazor
相聚时光
国庆
Https
Selenium
BootstrapBlazor
.NET8
内网穿透
nginx
zeroiter
家电
维修
Wordpress
ssh
爬虫
Typecho
羽裳
累计撰写
17
篇文章
累计收到
0
条评论
首页
栏目
《也许你也想建站?》
《代码的海洋》
《生活日常》
《技能get》
页面
友链
关于
用户登录
登录
找到
1
篇与
Swagger
相关的结果
2023-10-15
.Net6 Swagger文档设置同时支持 自定义分组+Api版本分组
.NET webApi 中Swagger默认是不会进行任何分组的,就只是罗列出来罢了。这样当用的时间长了,api变多了,项目变得复杂了,看起来就会很难受了,这时候对swagger的分组就变得很有必要了。网上的浏览下来,主要有两种分组方式:自定义分组、通过版本控制分组但这两种情况实际上在开发中都会出现,所以就在想要怎么才能同时满足两种分组方式,但实际上这两种方式都需要用到GroupName参数,其中一个总会覆盖另一个,网上也没有搜到现成的,只有自己动手撸了 😅 。(纯粹自己瞎整出来的,不一定是最佳方案,可以当作一种方向参考,也欢迎评论区讨论)先看最终显示效果吧:这里可以看到每个文档的分组条件格式是【自定义】:版本号,是不是看着还行 😋 虽然下拉框看着挺奇怪的,但在不改动前端的情况下也就只能先这么整了 😅 。下面直接看代码吧~首先是Swagger的配置信息这里定义了一个自定义分组Config,其中第一个是 默认分组,给那些不设置自定义分组的api留的,这个是必须要有的,后面的自己根据实际设置就行//Swagger 文档配置 "Swagger": { "Doc": { "Content": { "Name": "workbench-for-mr.liu", "Email": "---" }, "Description": ".NET6 WebAPI 文档 By workbench", "Title": ".NET6 WebAPI 文档" }, //自定义分组 "Config": [ { "GroupName": "", "Title": "【默认分组】" }, { "GroupName": "Open", "Title": "【开放接口】" }, { "GroupName": "Test", "Title": "【内部测试】" } ] }Program.cs配置Swgger根据前一步配置的自定义分组和api的版本控制(并过滤掉不需要的分组)生成Swagger文档//Swagger builder.Services.AddSwaggerGen(c => { #region 文档分组(自定义+版本控制) //根据API版本信息生成的API文档 var provider = builder.Services.BuildServiceProvider().GetRequiredService<IApiVersionDescriptionProvider>(); var _config = AppConfig.Get_appsettting<List<SwaggerConfig.groupConfig>>("Swagger:Config"); //当前所有的api var _apiDescriptionsProvider = builder.Services.BuildServiceProvider().GetService<Microsoft.AspNetCore.Mvc.ApiExplorer.IApiDescriptionGroupCollectionProvider>(); var appApis = _apiDescriptionsProvider.ApiDescriptionGroups.Items .SelectMany(group => group.Items); //自定义分组 _config.ForEach(group => { //版本号分组 foreach (var description in provider.ApiVersionDescriptions) { //是否存在符合的api var _api = appApis.Where(x => ((group.GroupName.Equals("") && !x.RelativePath.Contains(""))) && description.GroupName.Equals(x.GroupName)); if (_api.Count() > 0) { string _GName = (string.IsNullOrWhiteSpace(group.GroupName) ? "" : group.GroupName + ":") + description.GroupName; c.SwaggerDoc(_GName, new OpenApiInfo { Contact = new OpenApiContact { Name = AppConfig.Get_appsettting("Swagger:Doc:Content:Name"), Email = AppConfig.Get_appsettting("Swagger:Doc:Content:Email") }, Description = AppConfig.Get_appsettting("Swagger:Doc:Description"), Title = group.Title, Version = "v" + description.ApiVersion.ToString() }); } } }); //在Swagger文档显示的API地址中将版本信息参数替换为实际的版本号 c.DocInclusionPredicate((version, apiDescription) => { //= "api//v/WeatherForecast" var _GName = _config.Where(x => !string.IsNullOrWhiteSpace(x.GroupName) && apiDescription.RelativePath.Contains(x.GroupName)).FirstOrDefault()?.GroupName; var _GName2 = apiDescription.GroupName; if (!string.IsNullOrWhiteSpace(_GName)) _GName2 = _GName + ":" + _GName2; if (!version.Equals(_GName2)) return false; IEnumerable<string>? values = apiDescription!.RelativePath.Split('/').Select(x => Regex.Replace(x.Replace("v", apiDescription.GroupName), "\\", _GName ?? "")).Where(x => !string.IsNullOrWhiteSpace(x)); apiDescription.RelativePath = String.Join("/", values); return true; }); #endregionSwaggerUI 也需要同时设置 app.UseSwaggerUI(c => { #region 文档分组(自定义+版本控制) var provider = app.Services.GetRequiredService<IApiVersionDescriptionProvider>(); var _config = AppConfig.Get_appsettting<List<SwaggerConfig.groupConfig>>("Swagger:Config"); //当前所有的api var _apiDescriptionsProvider = builder.Services.BuildServiceProvider().GetService<Microsoft.AspNetCore.Mvc.ApiExplorer.IApiDescriptionGroupCollectionProvider>(); var appApis = _apiDescriptionsProvider.ApiDescriptionGroups.Items .SelectMany(group => group.Items); _config.ForEach(group => { foreach (var description in provider.ApiVersionDescriptions.Reverse()) { //是否存在符合的api var _api = appApis.Where(x => ((group.GroupName.Equals("") && !x.RelativePath.Contains(""))) && description.GroupName.Equals(x.GroupName)); if (_api.Count() > 0) { c.SwaggerEndpoint($"/swagger//swagger.json", group.Title + ":" + description.GroupName); //分组显示 } } }); #endregion });最后看看结果吧使用方式,[ApiVersion("0")]不变,和之前一样就行,至于[ApiExplorerSettings(GroupName ="")]由于会和API版本控制冲突,所以这个就不能用了,改成直接在路由前面加上特殊识别内容/,其中Test需要和前面设置的 自定义分组 配置项的GroupName一致才行,完整情况就像下面这样: /// <summary> /// 示例控制器 /// </summary> [Route("/v/[controller]")] [ApiController] [ApiVersion("0")] //[ApiExplorerSettings(GroupName ="")] public class WeatherForecastController : ControllerBase { [HttpGet] public ReturnInfo get() { return new ReturnInfo() ; } [HttpGet("ssssss")] [ApiVersion("3")] public ReturnInfo hhh() { return new ReturnInfo() ; } }可以看到,这里有两个api,其中一个将版本设置成了v3,Controller上添加了自定义分组Test,所以等会就会分成Test:v0和Test:v3两个文档但是,请求路径会多带一个Test,也会多出一个路径参数第一个/Test/,必须要留着(其实看着条理也挺清晰的,留着也还不错)第二个是路径参数,是因为我前面写的的关系,其实直接去掉就行了(但是我还是想跟正常的部分有个区分),也可以像下面这样,直接删除GName路径参数就行了(由于这是之前版本控制就配置好了的,所以直接就复制一份改改就行了)/// <summary> /// 取消swagger文档需要输入版本信息 /// </summary> public class RemoveVersionFromParameter : IOperationFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { var versionParameter = operation.Parameters.FirstOrDefault(p => p.Name == "version"); if (versionParameter != null) { operation.Parameters.Remove(versionParameter); } //也删掉GName路径参数 var versionParameter2 = operation.Parameters.FirstOrDefault(p => p.Name.Contains("gName")); if (versionParameter2 != null) { operation.Parameters.Remove(versionParameter2); } } }这时候再看也就没有多余的参数了,请求也是没问题的完事,大概就是这样 😏
2023年10月15日
22 阅读
0 评论
0 点赞