- 介绍
- 先决条件
- 具体说明
- 模块类添加
- 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认证的安全锁显示和枚举注释的显示等。
首先我们需要在此类中添加AddSwagger
和UseSwaggerUI
方法。具体形式如下:
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().Select(m => m.GroupName);
if (version.Any())
{
return version.Any(v => v == docName);
}
//这里获取action的特性
var actionVersion = method.GetCustomAttributes(true).OfType().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
,则其将在此分组中显示。
效果图
要实现接口的注释显示,首先应该把相应类库的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() } });
options.OperationFilter();
options.OperationFilter();
options.OperationFilter();
});
}
4、枚举注释的显示
如果没记错的话,swagger
是从版本3.x
开始使用了新的什么协议,网上也有写文章介绍了显示枚举注释的方法,但是都是基于2.x
版本的介绍。最终找到一个类似的解决方法,稍加整理形成一下方法。
其实核心的思路都是通过自定义一个继承自IDocumentFilter
接口的类来完成枚举的注释显示。
具体直接看代码吧。
public class EnumDocumentFilter : IDocumentFilter
{
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
Dictionary 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 list = new List();
foreach (var val in property.Enum)
{
list.Add((OpenApiInteger)val);
}
property.Description += DescribeEnum(itemType, list);
}
}
}
static Dictionary GetAllEnum()
{
Assembly ass = Assembly.Load("Hbw.Test.Domain.Shared");
Type[] types = ass.GetTypes();
Dictionary dict = new Dictionary();
foreach (Type item in types)
{
if (item.IsEnum)
{
dict.Add(item.Name, item);
}
}
return dict;
}
static string DescribeEnum(Type type, List enums)
{
if (type == null)
{
return string.Empty;
}
var enumDescriptions = new List();
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 $"{Environment.NewLine}{string.Join("" + 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();
最终的枚举注释显示效果如下:
以上基本完成了swagger
的单独配置工作,而如果要使用它,我们还需要在Hbw.Test.HttpApi.Host
项目中的模块类上添加依赖,具体如下:
[DependsOn(
...
typeof(TestSwaggerModule)
)]
public class TestHttpApiHostModule : AbpModule
{
...
}
总结
以上就是目前我在项目中使用到的swagger
的相关配置内容,这样处理的好处是,如果以后有新的配置需要添加,那单独修改这个类库即可,如果你希望把它形成nuget
包进行发布,也是很方便的。希望对你也有所帮助。