簡體   English   中英

.Net Core 3.1 swagger API 版本沖突命名空間 url

[英].Net Core 3.1 swagger API versioning conflicting namespaces url

我正在使用 swagger 來生成我的 API 文檔,現在我需要對我的一些端點進行版本控制。

所以我配置了 swagger 以正確識別我的版本和 map 端點。 但是 swagger 正在失去它的軌道,因為我在不同的命名空間上使用了相同的 class 名稱,我得到了這個錯誤:

Conflicting method/path combination "GET api/v1/A" for actions - TesteSwagger.Controllers.B.AController.x (TesteSwagger),TesteSwagger.Controllers.A.AController.x (TesteSwagger). Actions require a unique method/path combination for Swagger/OpenAPI 3.0. Use ConflictingActionsResolver as a workaround

這是我為重現它而制作的示例

我所有的 swagger 包都在版本 6.0.2 中。

我正在使用.Net Core 3.1 WebApi 默認空模板

啟動.cs:

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();

            services.AddApiVersioning(
                options => 
                {
                    options.ReportApiVersions = true;
                    options.DefaultApiVersion = new ApiVersion(1, 0);
                    options.AssumeDefaultVersionWhenUnspecified = true;
                });

            services.AddVersionedApiExplorer(
                options =>
                {
                    options.GroupNameFormat = "'v'VVV";
                    options.SubstituteApiVersionInUrl = true;
                });

            services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();

            services.AddSwaggerGen(options =>
            {
                options.CustomSchemaIds(x => x.FullName);
                options.DescribeAllParametersInCamelCase();
                options.OperationFilter<SwaggerDefaultValues>();
                options.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
            });
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IApiVersionDescriptionProvider provider)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseSwagger()
              .UseSwaggerUI(c =>
              {
                  c.DisplayRequestDuration();
                  foreach (var description in provider.ApiVersionDescriptions)
                  {
                      c.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json",
                          description.GroupName.ToUpperInvariant());
                  }
              });

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }

Swagger 默認配置類:

    public class SwaggerDefaultValues : IOperationFilter
    {
        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            
        }
    }

    public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions>
    {
        public void Configure(SwaggerGenOptions options)
        {
        }
    }

Controller (v1):

namespace TesteSwagger.Controllers.A
{
    [ApiController, ApiVersion("1.0")]
    [Route("api/v{version:apiVersion}/[controller]")]
    public class AController : ControllerBase
    {
        [HttpPost]
        [ProducesResponseType(typeof(B), (int)HttpStatusCode.OK)]
        public IActionResult x(A a) => Ok(new B());
    }

    public class A
    {
        public int Foo { get; set; }
    }

    public class B
    {
        public int Bar { get; set; }
    }
}

B Controller (v2):

namespace TesteSwagger.Controllers.B
{
    [ApiController, ApiVersion("2.0")]
    [Route("api/v{version:apiVersion}/[controller]")]
    public class AController : ControllerBase
    {
        [HttpPost]
        [ProducesResponseType(typeof(B), (int)HttpStatusCode.OK)]
        public IActionResult x(A a) => Ok(new B());
    }

    public class A
    {
        public int Foo { get; set; }
    }

    public class B
    {
        public int Bar { get; set; }
    }
}

僅當我將其更改為 v2 時,此錯誤才會在屏幕上顯示:

Fetch error
undefined /swagger/v2/swagger.json

我使用在 v1 URL 上生成的 curl 進行測試,一切正常,只是 swagger 不明白

// works great
curl -X POST "https://localhost:44312/api/v1/A" -H  "accept: text/plain" -H  "Content-Type: application/json" -d "{\"foo\":0}"

// works great
curl -X POST "https://localhost:44312/api/v2/A" -H  "accept: text/plain" -H  "Content-Type: application/json" -d "{\"foo\":0}"

我真的不知道是我做錯了什么還是 swagger 真的不支持這種版本控制。

有任何想法嗎?

首先,類型的名稱在很大程度上是不相關的。 命名空間不是一個通常可以通過 HTTP 傳達的概念,並且高度依賴於媒體類型。 現代 JavaScript 確實有模塊,但它不是一個命名空間。 無論如何,一個 .NET 命名空間不會變成一組 JavaScript 模塊以在 JSON 中表示; 當然,不是默認的。

這里的系統性問題似乎是您定義了一個沒有任何實際配置的 Swashbuckle 配置。 要使所有部分組合在一起,必須先做三件事:

  1. 添加版本化 API 資源管理器- 提供 API 版本化擴展,使用格式化的 API 版本將ApiDescription.GroupName整理成組。 在通過 URL 段進行版本控制時, AddVersionedApiExplorer中的配置有助於將其與典型的 Swashbuckle 格式和示例保持一致。
  2. 添加 Swagger 端點- 通過UseSwaggerUI 每個 API 版本預計將是一個端點。 段值通常映射到 API 版本組名稱(例如格式化版本)
  3. 添加 Swagger 文檔- 配置 Swashbuckle 以定義每個 API 版本的 Open API(以前稱為 Swagger)文檔。 文檔的鍵映射到ApiDescription.GroupName和 #2 中定義的端點段。

您沒有在 #3 中提供任何實現或配置。 因此,Swashbuckle 假設只有一個文檔。 由於您在同一個文檔中具有相同名稱模型,因此您會收到文檔生成錯誤。 同一文檔中不能有重復的路徑路徑或 model 名稱。 但是,當您為每個 API 版本定義文檔時,您可以在多個版本中擁有重復的 model 名稱。

旁注在同一 API 版本中可能有重復的 .NET 類型名稱,但您必須提供別名。 命名空間從不考慮獨特性。 除非它真的沒有意義,否則我建議您在每組版本化 API 中為 model 名稱使用唯一類型/類。

ASP.NET API 版本控制Swagger 示例演示了配置的整體外觀。 典型的配置如下所示:

public void Configure( SwaggerGenOptions options )
{
    // configure Swashbuckle to define a Swagger document per defined API version
    foreach ( var description in provider.ApiVersionDescriptions )
    {
        options.SwaggerDoc(
            description.GroupName,
            new OpenApiInfo()
            {
                Title = "API " + description.GroupName,
                Version = description.ApiVersion.ToString(),
            } );
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM