文章目录

  • 介绍
  • 先决条件
  • 具体说明
    • 模块类添加
    • Swagger配置类
      • 1、接口分组
      • 2、接口注释
      • 3、JWT认证的安全锁显示
      • 4、枚举注释的显示
  • 总结

介绍

现在大多工作中用到的后端开发都是基于RESTFUL的接口开发了,所以使用swagger进行接口管理也就成了比较默认的方式。最近相对比较有时间,所以觉得可以把在abp vnext中使用swagger的一些知识点进行一下总结。

先决条件

  • VS 2019
  • Abp VNext 的版本号:4.0.0
  • Swashbuckle.AspNetCore 版本号:5.5.0
  • Swashbuckle.AspNetCore.Filters 版本号:6.1.0

具体说明

因为abp vnext中对模块的概念使用比较多,所以这里我们也使用这种方式。将swagger的相关配置放到单独的类库中,在XXX.HttpApi.Host项目中添加相应的依赖模块来完成最终的swagger配置工作。

我们已类库:Hbw.Test.Swagger作为此文的说明案例。

模块类添加

添加一个TestSwaggerModule类,具体代码如下:

using Volo.Abp;
using Volo.Abp.Modularity;namespace Hbw.Test.Swagger
{public class TestSwaggerModule : AbpModule{public override void ConfigureServices(ServiceConfigurationContext context){context.Services.AddSwagger();}public override void OnApplicationInitialization(ApplicationInitializationContext context){context.GetApplicationBuilder().UseSwaggerUI();}}
}

Swagger配置类

添加一个扩展类来完成swagger的具体配置工作,类名为:TestSwaggerExtensions 。关于接口的配置,我主要介绍一下几个点:接口分组、接口注释添加、JWT认证的安全锁显示和枚举注释的显示等。

首先我们需要在此类中添加AddSwaggerUseSwaggerUI方法。具体形式如下:

public static IServiceCollection AddSwagger(this IServiceCollection services)
{...
}public static void UseSwaggerUI(this IApplicationBuilder app)
{...
}

1、接口分组

接口的分组主要通过SwaggerDoc来完成,然后通过DocInclusionPredicate方法完成具体的接口在哪个组中进行显示,最后通过SwaggerEndpoint方法将配置好的分组内容放到对应的json文件中。

下面我们来具体的看看实现的过程。

  • SwaggerDoc
public static IServiceCollection AddSwagger(this IServiceCollection services)
{return services.AddSwaggerGen(options =>{options.SwaggerDoc("thridapi_v1", new OpenApiInfo{Title = "第三方数据API",Version = "v1",Description = "xxxxxxxxx系统第三方数据 v1.0 接口服务"});options.SwaggerDoc("system_v1", new OpenApiInfo{Title = "系统API",Version = "v1",Description = "xxxxxxxxx系统 v1.0 接口服务"});});
}
  • DocInclusionPredicate
public static IServiceCollection AddSwagger(this IServiceCollection services)
{return services.AddSwaggerGen(options =>{...options.DocInclusionPredicate((docName, description) =>{if (!description.TryGetMethodInfo(out MethodInfo method)){return false;}/*使用ApiExplorerSettingsAttribute里面的GroupName进行特性标识* DeclaringType只能获取controller上的特性* 我们这里是想以action的特性为主* */var version = method.DeclaringType.GetCustomAttributes(true).OfType<ApiExplorerSettingsAttribute>().Select(m => m.GroupName);if (version.Any()){return version.Any(v => v == docName);}//这里获取action的特性var actionVersion = method.GetCustomAttributes(true).OfType<ApiExplorerSettingsAttribute>().Select(m => m.GroupName);if (actionVersion.Any()){return actionVersion.Any(v => v == docName);}return false;});});
}

说明:

1、如果DocInclusionPredicate方法中直接返回true,则显示所有的接口,分组也就无效了。

2、通过上面的方法,也可以把abp vnext中默认生成的接口进行隐藏。

  • SwaggerEndpoint
public static void UseSwaggerUI(this IApplicationBuilder app)
{app.UseSwagger();app.UseSwaggerUI(c =>{c.SwaggerEndpoint("/swagger/thridapi_v1/swagger.json", "第三方数据API");c.SwaggerEndpoint("/swagger/system_v1/swagger.json", "系统API");c.RoutePrefix = string.Empty;  // url 中不显示swagger});
}

在完成了上面所有配置后,还有一个地方需要处理才能实现最终的效果。那就是具体的api接口方法上,或者webapi的控制器上添加ApiExplorerSettings属性。

[ApiExplorerSettings(GroupName = "system_v1")]
public string Hello(string name)
{return $"{name}你好";
}

因为上面使用的分组是system_v1,所以Hello将会在这个分组中显示;如果使用的是thridapi_v1,则其将在此分组中显示。

效果图

2、接口注释

要实现接口的注释显示,首先应该把相应类库的xml文件生成出来。具体可以右击对应项目的【属性】,在【生成】选项卡中的【输出】部分,勾选“XML文档文件”即可。

然后在swagger中进行相应的配置,代码如下:

public static IServiceCollection AddSwagger(this IServiceCollection services)
{return services.AddSwaggerGen(options =>{...//获取应用程序所在目录(绝对,不受工作目录影响,建议采用此方法获取路径)var basePath = Path.GetDirectoryName(typeof(TestSwaggerModule)Assembly.Location);var xmlPath = Path.Combine(basePath, "xxxxx.xml");//这个就是刚刚配置的xml文件名//默认的第二个参数是false,对方法的注释// 即swagger界面只有方法有注释,最上面的控制器没有注释// 而第二个参数为true, 则是controller的注释options.IncludeXmlComments(xmlPath, true);});
}

3、JWT认证的安全锁显示

直接上代码,如下:

public static IServiceCollection AddSwagger(this IServiceCollection services)
{return services.AddSwaggerGen(options =>{...var security = new OpenApiSecurityScheme{Description = "JWT模式授权,请输入 Bearer {Token} 进行身份验证",Name = "Authorization",In = ParameterLocation.Header,Type = SecuritySchemeType.ApiKey};// 必须 oauth2 这个名称options.AddSecurityDefinition("oauth2", security);options.AddSecurityRequirement(new OpenApiSecurityRequirement { {security, new List<string>() } });options.OperationFilter<AddResponseHeadersFilter>();options.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();options.OperationFilter<SecurityRequirementsOperationFilter>();});
}

4、枚举注释的显示

如果没记错的话,swagger是从版本3.x开始使用了新的什么协议,网上也有写文章介绍了显示枚举注释的方法,但是都是基于2.x版本的介绍。最终找到一个类似的解决方法,稍加整理形成一下方法。

其实核心的思路都是通过自定义一个继承自IDocumentFilter接口的类来完成枚举的注释显示。

具体直接看代码吧。

public class EnumDocumentFilter : IDocumentFilter
{public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context){Dictionary<string, Type> dict = GetAllEnum();foreach (var item in swaggerDoc.Components.Schemas){var property = item.Value;var typeName = item.Key;Type itemType = null;if (property.Enum != null && property.Enum.Count > 0){if (dict.ContainsKey(typeName)){itemType = dict[typeName];List<OpenApiInteger> list = new List<OpenApiInteger>();foreach (var val in property.Enum){list.Add((OpenApiInteger)val);}property.Description += DescribeEnum(itemType, list);}}}static Dictionary<string, Type> GetAllEnum(){Assembly ass = Assembly.Load("Hbw.Test.Domain.Shared");Type[] types = ass.GetTypes();Dictionary<string, Type> dict = new Dictionary<string, Type>();foreach (Type item in types){if (item.IsEnum){dict.Add(item.Name, item);}}return dict;}static string DescribeEnum(Type type, List<OpenApiInteger> enums){if (type == null){return string.Empty;}var enumDescriptions = new List<string>();foreach (var item in enums){var value = Enum.Parse(type, item.Value.ToString());var desc = GetDescription(type, value);if (string.IsNullOrEmpty(desc)){enumDescriptions.Add($"{item.Value}:{Enum.GetName(type, value)}; ");}else{enumDescriptions.Add($"{item.Value}:{Enum.GetName(type, value)}, {desc}; ");}}return $"<br/>{Environment.NewLine}{string.Join("<br/>" + Environment.NewLine, enumDescriptions)}";}static string GetDescription(Type t, object value){foreach (MemberInfo mInfo in t.GetMembers()){if (mInfo.Name == t.GetEnumName(value)){foreach (Attribute attr in Attribute.GetCustomAttributes(mInfo)){if (attr.GetType() == typeof(DescriptionAttribute)){return ((DescriptionAttribute)attr).Description;}}}}return string.Empty;}}
}

代码中的GetAllEnum方法中,第一行加载的程序集是定义枚举的类库文件,在abp vnext中也就是Hbw.Test.Domain.Shared这个库,所以这里把相应的项目类库名称放在此处即可。

完成这个类的定义后,我们需要在添加安全锁的代码的最后添加如下代码即可。

options.DocumentFilter<EnumDocumentFilter>();

最终的枚举注释显示效果如下:

以上基本完成了swagger的单独配置工作,而如果要使用它,我们还需要在Hbw.Test.HttpApi.Host项目中的模块类上添加依赖,具体如下:

[DependsOn(...typeof(TestSwaggerModule))]
public class TestHttpApiHostModule : AbpModule
{...
}

总结

以上就是目前我在项目中使用到的swagger的相关配置内容,这样处理的好处是,如果以后有新的配置需要添加,那单独修改这个类库即可,如果你希望把它形成nuget包进行发布,也是很方便的。希望对你也有所帮助。

abp vnext中swagger使用小结相关推荐

  1. 四、Abp Vnext中使用Minio打造文件管理模块(上)

    在Abp商业版本中已经提供了文件管理模块的,免费版本是没有的,本文将介绍如何使用Minio打造一个自己的文件管理模块. 在项目开始之前,需要先安装一个Minio服务,可以在本地pc或云主机中安装,具体 ...

  2. 六、Abp Vnext 中Efcore的多模块关联查询

    abp框架提供了非常棒的模块开发体验,这些模块是可复用的,并且也适用于开发微服务:既然模块可以独立发布,那么它的数据库配置也是独立的,对于使用efcore的模块,每个模块中都包含一个不同的Dbcont ...

  3. ABP Vnext中使用Magicodes.IE导入导出

    文章目录 ABP Vnext中使用Magicodes.IE导入导出 1.Moudle中配置 2.构造函数注入 3.导出 3.1 导出实体 3.2 导出 4.导入 4.1 导入实体 4.2 导入 5.[ ...

  4. ABP vNext中使用开源日志面板 LogDashboard

    ABP vNext 使用 logdashboard 本文示例源码: https://github.com/liangshiw/LogDashboard/tree/master/samples/abpv ...

  5. 在 ABP vNext 中编写仓储单元测试的问题一则

    一.问题 新项目是基于 ABP vNext 框架进行开发的,所以我要求为每层编写单元测试.在同事为某个仓储编写单元测试的时候,发现了一个奇怪的问题.他的对某个聚合根的 A 字段进行了更新,随后对某个导 ...

  6. 八、Abp Vnext中为模块添加设置管理

    在项目中,我们要进行一些参数配置,通常是使用aspnetcore的配置系统,通过appsettings.json来存储配置参数:Abp框架也包含了一套完善的设备管理模块,使用它可以很方便的从不同维度获 ...

  7. 『ABP』ABP vNext中使用开源日志面板 LogDashboard

  8. ABP VNext从单体切换到微服务

    注:此处的微服务只考虑服务部分,不考虑内外层网关.认证等. ABP VNext从单体切换到微服务,提供了相当大的便利性,对于各模块内部不要做任何调整,仅需要调整承载体即可. ABP can help ...

  9. ABP vNext 的实体与服务扩展技巧分享

    使用 ABP vNext 有一个月左右啦,这中间最大的一个收获是:ABP vNext 的开发效率真的是非常好,只要你愿意取遵循它模块化.DDD 的设计思想.因为官方默认实现了身份.审计.权限.定时任务 ...

最新文章

  1. modoer点评系统3.5_丰田“奥拓”正式亮相,油耗3.5L,配软顶敞篷+四开门,或4万起...
  2. 苹果开始整治App Store恶意抄袭现象
  3. 一幅图看懂Python编程
  4. php使用redis持久化,redis如何持久化
  5. 用按钮控制游戏物件的开启及关闭
  6. Java List集合转换相关操作
  7. 京东商品及评论爬虫(selenium)
  8. C++ 长指针与指针的区别
  9. 七年师大,青春永不毕业
  10. 使用Gson 解析json文件
  11. Aria2 安装和使用全教程
  12. 【每日一题】一起冲击蓝桥杯吧——Day2【蓝桥真题】
  13. 【Python 高级】Python全栈体系(七)
  14. 常用的Transformation
  15. 如何删除PDF文档中的某一页
  16. AVFrame结构体中变量解释
  17. Vim配置及使用技巧
  18. 智慧城市篇 | 数字孪生智慧排水管网管理平台
  19. NAO机器人的多功能
  20. ITAIP 培训通知|第三期“信创经理人研修班”高级决策人员报名中

热门文章

  1. 米的换算单位和公式_小学三年级数学常用公式和单位换算,孩子复习宝典!
  2. ipad远程连接虚拟机linux,如何从ipad pro上通过SSH远程Linux
  3. java 编译class_.java文件怎样编译成.class文件,你值得一看的技巧
  4. 电商新春农历年春节海报还没设计?这是你需要的新年Banner灵感!
  5. 百搭电商背景素材,设计师应急PSD分层模板
  6. java rpc 框架 常用_常用的RPC架构系列---gRPC
  7. Linux内存管理 brk(),mmap()系统调用源码分析2:brk()的内存释放流程
  8. webapi 路由限制命名控件_什么是命名数据网络NDN?
  9. Ubuntu20.04搭建ftp服务(亲测通过)
  10. android studio的一个bug