在asp.net核心3.1 web api中,分组和版本控制不能很好地协同工作



我正在使用Asp.Net Core 3.1构建我的API。我正在使用swagger为我的API生成文档。我决定根据控制器对我的招摇文件进行分组。所以我最终做了这样的事,

启动-配置服务:

options.SwaggerDoc(
"LibraryOpenAPISpecificationCategories",
...

启动-配置:

options.SwaggerEndpoint(
"/swagger/LibraryOpenAPISpecificationCategories/swagger.json",
"Library API (Categories)");

控制器:

[Route("api/categories")]
[ApiController]
[ApiExplorerSettings(GroupName = "LibraryOpenAPISpecificationCategories")]
public class CategoriesController : ControllerBase

在此之前,一切都很顺利。当我添加版本控制时,Swagger文档停止在控制器中显示方法。我试图在版本内部进行分组,这样每个版本都会有像这样的组

V1->LibraryOpenAPI规范类别

V1->LibraryOpenAPI规范项目

V2->库OpenAPI规范类别

V2->库OpenAPI规范项

以下是我所做的,

启动-配置服务:

services.AddVersionedApiExplorer(options =>
{
options.GroupNameFormat = "'v'VV";
});
services.AddApiVersioning(options =>
{
options.AssumeDefaultVersionWhenUnspecified = true;
options.DefaultApiVersion = new ApiVersion(1, 0);
options.ReportApiVersions = true;
});
var apiVersionDescriptionProvider =
services.BuildServiceProvider().GetService<IApiVersionDescriptionProvider>();
services.AddSwaggerGen(options =>
{
foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions)
{
options.SwaggerDoc(
$"LibraryOpenAPISpecificationCategories{description.GroupName}",
...

启动-配置:

app.UseSwaggerUI(options =>
{
foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions)
{
options.SwaggerEndpoint(
$"/swagger/LibraryOpenAPISpecificationCategories{description.GroupName}/swagger.json",
$"Library API (Categories) {description.GroupName.ToUpperInvariant()}");

控制器:

[Route("api/categories")]
[ApiController]
[ApiExplorerSettings(GroupName = "LibraryOpenAPISpecificationCategories")]
public class CategoriesController : ControllerBase

型锻文档中未显示错误。请帮我解决哪里出了问题。我遗漏了什么吗?

经过一些分析,我发现我的ConfigureServices中的AddSwaggerGen中遗漏了DocInclusionPredicate

以下是我的解决方法,

options.DocInclusionPredicate((documentName, apiDescription) =>
{
var actionApiVersionModel = apiDescription.ActionDescriptor
.GetApiVersionModel(ApiVersionMapping.Explicit | ApiVersionMapping.Implicit);
var apiExplorerSettingsAttribute = (ApiExplorerSettingsAttribute)apiDescription.ActionDescriptor.EndpointMetadata.First(x => x.GetType().Equals(typeof(ApiExplorerSettingsAttribute)));
if (actionApiVersionModel == null)
{
return true;
}
if (actionApiVersionModel.DeclaredApiVersions.Any())
{
return actionApiVersionModel.DeclaredApiVersions.Any(v =>
$"{apiExplorerSettingsAttribute.GroupName}v{v.ToString()}" == documentName);
}
return actionApiVersionModel.ImplementedApiVersions.Any(v =>
$"{apiExplorerSettingsAttribute.GroupName}v{v.ToString()}" == documentName);
});

希望这能帮助到其他人。

由于一些人在不同的地方要求这样做,下面是如何实现自定义的IApiDescriptionProvider。它只是在处理结束时更新ApiDescription.GroupName。这将完全独立于Swashbuckle或任何其他OpenAPI/Swagger文档生成器:

public class CollateApiDescriptionProvider : IApiDescriptionProvider
{
readonly IOptions<ApiExplorerOptions> options;
public CollateApiDescriptionProvider( IOptions<ApiExplorerOptions> options ) =>
this.options = options;
public int Order => 0;
public void OnProvidersExecuting( ApiDescriptionProviderContext context ) { }
public void OnProvidersExecuted( ApiDescriptionProviderContext context )
{
var results = context.Results;
var format = options.Value.GroupNameFormat;
var text = new StringBuilder();
for ( var i = 0; i < results.Count; i++ )
{
var result = results[i];
var action = result.ActionDescriptor;
var version = result.GetApiVersion();
var groupName = action.GetProperty<ApiDescriptionActionData>()?.GroupName;
text.Clear();
// add the formatted API version according to the configuration
text.Append( version.ToString( format, null ) )
// if there's a group name, prepend it
if ( !string.IsNullOrEmpty( groupName ) )
{
text.Insert( 0, ' ' );
text.Insert( 0, groupName );
}
result.GroupName = text.ToString();
}
}
}

要注册您的新提供商,请将其添加到服务集合:

services.TryAddEnumerable(
ServiceDescriptor.Transient<IApiDescriptionProvider, CollateApiDescriptionProvider>() );

注意:这应该发生在services.AddApiVersioning()之后

您可以随心所欲地使用组名称,但要注意,您不能创建多级分组。它根本没有开箱即用的支持。在大多数情况下,每个API版本只能有一个OpenAPI/Swagger文档。这是因为URL在文档中必须是唯一的。

从技术上讲,可以在多个级别上进行分组,但这需要对UI和文档生成过程进行一些更改。我只见过少数人愿意投入这么多精力。他们有效地创建了自己的UI和文档生成后端。

最新更新