【问题标题】:Grouping and Versioning not working well together in swagger in asp.net core 3.1 web api在 asp.net core 3.1 web api 中,分组和版本控制不能很好地协同工作
【发布时间】:2020-06-13 22:22:34
【问题描述】:

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

启动 - ConfigureServices:

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 -> 库OpenAPISpecificationCategories

V1 -> LibraryOpenAPISpecificationItems

V2 -> 库OpenAPISpecificationCategories

V2 -> 库OpenAPISpecificationItems

这就是我所做的,

启动 - ConfigureServices:

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

swagger 文档中没有显示错误。请帮助我解决我哪里出错了。我错过了什么吗?

【问题讨论】:

  • 我好像不见了DocInclusionPredicate

标签: c# swagger asp.net-core-webapi swashbuckle api-versioning


【解决方案1】:

经过一番分析,我发现我在AddSwaggerGen 中错过了DocInclusionPredicate 在我的ConfigureServices 中。

这是我的解决方法,

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);
});

希望这对那里的人有所帮助。

【讨论】:

  • 感谢您的加入,它帮助我获得了包含多个 swagger 文档的有效解决方案!
  • 这可行,但我建议使用自定义 IApiDescriptionProvider 来重新整理 ApiDescription 实例。 API Explorer 仅支持单层组织(例如GroupName)。从逻辑上讲,这应该是默认的 API 版本。在 API 版本 5.0+ 之前,您在 ApiExplorerSettings.GroupName 中输入的任何显式任何显式值都会被覆盖。虽然您可以(现在)提供您自己的组名,但将它们全部放在一个 OpenAPI 文档中将取决于您的版本控制方式。每个 API 版本通常需要 1 个文档。
  • 最终,API Versioning 自己的 IApiDescriptionProvider 只提供基本功能。 1. 为 API 版本参数添加参数描述符。 2. 按 API 版本设置和整理 API 描述。创建您自己的提供程序并在最后重新组织事物并不需要太多工作。
【解决方案2】:

由于一些人在不同的地方提出了这个要求,以下是实现自定义 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 和文档生成后端。

【讨论】:

    猜你喜欢
    • 2016-12-08
    • 2020-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-14
    • 2016-05-14
    • 2018-01-18
    • 1970-01-01
    相关资源
    最近更新 更多