0

我有一个 ASP.NET Core (3.1) API,它使用aspnet-api-versioning (4.1.1) 库进行版本控制。该项目设置为从 URL 读取版本,如果未指定版本,则使用默认版本 (1)。示例控制器支持两个 API 版本(1 和 2)并且有两个相同的方法,每个版本一个。由于支持默认版本,因此控制器上有两个 Route 属性,一个没有版本,一个有。

在为 API 生成 OpenAPI 文档时,使用Swashbuckle.AspNetCore (5.6.3) 库,API 版本 1 和 2 的文档都将包含非版本化路由;“/客户/{externalCustomerId}”。要解决的问题是,如何将 Swagger 生成配置为仅包含默认版本的文档中的非版本化路由?鉴于下面的代码,版本 1 的文档应该是:

  • /客户/{externalCustomerId}
  • /v1/Customer/[externalCustomerId}

并且版本 2 的文档应该是:

  • /v2/Customer/{externalCustomerId}

启动:

public class Startup
{
    ... // Removed for brevity. Method below called from ConfigureServices(...).
    private static void ConfigureApiVersioning(IServiceCollection services)
    {
        services.AddVersionedApiExplorer(setup =>
        {
            setup.GroupNameFormat = "'v'V";
            setup.SubstituteApiVersionInUrl = true;
        });

        services.AddApiVersioning(setup =>
        {
            setup.AssumeDefaultVersionWhenUnspecified = true;
            setup.DefaultApiVersion = new ApiVersion(majorVersion: 1, minorVersion: 0);
            setup.ReportApiVersions = true;
            setup.ApiVersionReader = new UrlSegmentApiVersionReader();
        });
    }
}

控制器:

[Route("Customer")]
[Route("v{version:apiVersion}/Customer")]
[ApiVersion("1", Deprecated = true)]
[ApiVersion("2")]
[ApiController]
public class CustomerController : ControllerBase
{
    [HttpGet("{externalCustomerId}")]
    [MapToApiVersion("1")]
    public string Get()
    {
        return "Customer Api v1 responded with 200 ok";
    }

    [HttpGet("{externalCustomerId}")]
    [MapToApiVersion("2")]
    public string GetV2()
    {
        return "Customer Api v2 responded with 200 ok";
    }
}

可以(应该)以SwaggerGenOptions.DocInclusionPredicate()某种方式解决它吗?我试了一下,但找不到从ApiVersion谓词中获取默认 API 版本的方法。

一种选择可能是从DefaultApiVersionDescriptionProvider(或实现IApiVersionDescriptionProvider)继承来访问 Options 属性,这将允许我们获取默认 API 版本并在 Startup for 中使用带有闭包的谓词SwaggerGenOptions.DocInclusionPredicate(),但这是一个好方法吗?还有哪些其他选择?

4

1 回答 1

0

有几种可能性:

  • 利用DocInclusionPredicate
  • 使用自定义IOperationFilter
  • 使用自定义IApiDescriptionProvider

第一个可能是最简单的。由于所有正确版本的路由都包含路由参数,因此您只需排除任何包含它的路由。就像是:

c.DocInclusionPredicate((d, api) => !api.RelativePath.Contains("v{version:apiVersion}"))

您需要删除/禁用options.SubstituteApiVersionInUrl;无论如何,您都没有使用它。

您应该仔细考虑您的 API 文档所传达的内容;这是误导。OpenAPI/Swagger 文档将显示正确的路由2.0;但是,当客户请求它时,他们会得到1.0. 发生这种情况是因为您不允许指定任何版本并且您假设1.0. 您可以使用备用IApiVersionSelector,例如CurrentImplementationApiVersionSelector,但这只会扭转问题。版本控制的目的是让客户可以明确地询问他们想要的版本。

于 2020-10-28T21:13:08.900 回答