内容目录
首先是中间件,它决定了有时间显示哪些分组。
可以从 IApiDescriptionGroupCollectionProvider 服务中获取所有 API,然后通过 API 进行识别,检查是否有分组。
if (context.HostingEnvironment.IsDevelopment())
{
app.UseSwagger();
var descriptionProvider = app.ApplicationServices.GetRequiredService<IApiDescriptionGroupCollectionProvider>();
app.UseSwaggerUI(options =>
{
// 默认的
options.SwaggerEndpoint($"v1/swagger.json", "v1");
foreach (var description in descriptionProvider.ApiDescriptionGroups.Items)
{
if (description.GroupName == null) continue;
options.SwaggerEndpoint($"{description.GroupName}/swagger.json", description.GroupName);
}
});
}
为什么要先配置中间件而不是服务呢。
因为服务注入是延时执行,并不会在程序启动时即加载,最先加载的是中间件管道,中间件管道决定了右上角显示什么列表。
接下来看看服务注入。
服务注入分为两个部分,第一个部分生成文档地址,第二部分是动态筛选这个文档显示的 API 列表。
public static class SwaggerHelper
{
private static readonly HashSet<MethodInfo> Default = new HashSet<MethodInfo>();
public static void AddMySwaggerGen(this IServiceCollection services, Action<SwaggerGenOptions> setupAction = null)
{
services.AddSwaggerGen(options =>
{
setupAction.Invoke(options);
var descriptionProvider = services.BuildServiceProvider().GetRequiredService<IApiDescriptionGroupCollectionProvider>();
foreach (var description in descriptionProvider.ApiDescriptionGroups.Items)
{
if (description.GroupName == null)
{
options.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1",
Title = "v1",
Description = "默认"
});
foreach (var item in description.Items)
{
if (item.TryGetMethodInfo(out var methodInfo))
Default.Add(methodInfo);
}
}
else
{
options.SwaggerDoc(description.GroupName, new OpenApiInfo
{
Version = "v1",
Title = description.GroupName,
});
}
}
var dir = new DirectoryInfo(AppContext.BaseDirectory);
var files = dir.GetFiles().Where(x => x.Name.EndsWith(".xml")).ToArray();
foreach (var item in files)
{
options.IncludeXmlComments(item.FullName);
}
options.DoGroups();
});
}
public static void DoGroups(this SwaggerGenOptions swaggerGenOptions)
{
// docname == GroupName
swaggerGenOptions.DocInclusionPredicate((docname, b) =>
{
if (!b.TryGetMethodInfo(out MethodInfo methodInfo)) return false;
if (docname == "v1")
{
return Default.Any(x => x == methodInfo);
}
var ver = methodInfo.DeclaringType.GetCustomAttributes(true)
.OfType<ApiExplorerSettingsAttribute>()
.FirstOrDefault();
if (ver == null) return false;
return b.GroupName == docname;
});
}
}
首先是生成文档,我们需要将没有设置 GroupName 的 Controller 放在一个默认分组中。
然后是 SwaggerGenOptions.DocInclusionPredicate
,可以动态生成 swagger.json,由于默认分组中的 API 没有 GroupName,因此我们需要判断筛选列表,这样用户通过不同的 GroupName 访问的 swagger.json 都是不同的。
然后直接注入服务即可:
services.AddMySwaggerGen(options =>
{
});
文章评论