[英]Grouping and Versioning not working well together in swagger in asp.net core 3.1 web api
[英].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 配置。 要使所有部分组合在一起,必须先做三件事:
ApiDescription.GroupName
整理成组。 在通过 URL 段进行版本控制时, AddVersionedApiExplorer
中的配置有助于将其与典型的 Swashbuckle 格式和示例保持一致。UseSwaggerUI
。 每个 API 版本预计将是一个端点。 段值通常映射到 API 版本组名称(例如格式化版本)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.