我在解决方案中设置了以下控制器:
如上所述,路径不同是因为传递到路由中的版本参数导致了这种差异。此外,纯粹为了表示代码可以通过文档获得而创建全新方法是没有意义的,因此我的问题是为什么Swagger会忽略路径中的版本差异,并建议使用ConflictingActionsResolver?
此外,进一步调查后发现很多其他人也遇到了相同的问题(特别是头部版本控制的问题),而Swagger的严格做法与此相冲突。通常的解决方法似乎是使用冲突动作解析器(conflicting actions resolver)来仅获取遇到的第一个描述,这样API文档中只会显示1.0版本的内容,而省略了1.1版本的内容,在Swagger中给人的印象是该端点没有1.1版本。
如何解决这个问题,并在不创建新方法的情况下正确显示Swagger中可用的端点?这似乎是Swagger规范的一个疏漏,我们应该如何做?非常感谢您的帮助。
注意:许多人可能建议在路由末尾附加操作,但我们希望避免这种情况,因为这意味着我们的端点不符合RESTful规范。我们希望像customers/1这样的格式,使用GET、POST、PUT属性派生CRUD操作,而不必追加类似于customers/add_customer_1或customers/add_customer_2的内容反映URL中的方法名称。
[Route("api/v{VersionId}/[controller]")]
[ApiController]
[Produces("application/json")]
[Consumes("application/json")]
public class MyBaseController : ControllerBase
{
}
[ApiVersion("1.0")]
[ApiVersion("1.1")]
public class AuthenticationController : MyBaseController
{
private readonly ILoginService _loginService;
public AuthenticationController(ILoginService loginService)
{
_loginService = loginService;
}
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[HttpPost("login")]
public ActionResult<v1.JwtTokenResponse> Login([FromBody] v1.LoginRequest loginRequest)
{
var loginResult = _loginService.Login(loginRequest.Email, loginRequest.Password);
if (loginResult.StatusCode != HttpStatusCode.OK)
{
return StatusCode((int)loginResult.StatusCode);
}
var tokenResponse = new v1.JwtTokenResponse() { Token = loginResult.Token };
return Ok(tokenResponse);
}
}
在我的 API 的两个版本之间,这个方法没有发生任何变化,因此在我的文档中逻辑上应该显示该方法仍然支持新版本。假设我们有一个客户的第二个控制器,它的一些逻辑已经改变,这就是为什么我们有了新的 1.1 版本,因为语义化版本控制规定必须添加一些新内容,但以向后兼容的方式。
运行此代码时,一切都自然构建良好。代码正确无误,.net core 允许此类实现,但是,当涉及到 Swagger gen 时,我遇到了以下错误:
NotSupportedException: Conflicting method/path combination "POST api/v{VersionId}/Authentication/login" for actions - Template.Api.Endpoints.Controllers.AuthenticationController.Login (Template.Api.Endpoints),Template.Api.Endpoints.Controllers.AuthenticationController.Login (Template.Api.Endpoints). Actions require a unique method/path combination for Swagger/OpenAPI 3.0. Use ConflictingActionsResolver as a workaround
如上所述,路径不同是因为传递到路由中的版本参数导致了这种差异。此外,纯粹为了表示代码可以通过文档获得而创建全新方法是没有意义的,因此我的问题是为什么Swagger会忽略路径中的版本差异,并建议使用ConflictingActionsResolver?
此外,进一步调查后发现很多其他人也遇到了相同的问题(特别是头部版本控制的问题),而Swagger的严格做法与此相冲突。通常的解决方法似乎是使用冲突动作解析器(conflicting actions resolver)来仅获取遇到的第一个描述,这样API文档中只会显示1.0版本的内容,而省略了1.1版本的内容,在Swagger中给人的印象是该端点没有1.1版本。
Swagger UI Config
app.UseSwaggerUI(setup =>
{
setup.RoutePrefix = string.Empty;
foreach (var description in apiVersions.ApiVersionDescriptions)
{
setup.SwaggerEndpoint($"/swagger/OpenAPISpecification{description.GroupName}/swagger.json",
description.GroupName.ToUpperInvariant());
}
});
如何解决这个问题,并在不创建新方法的情况下正确显示Swagger中可用的端点?这似乎是Swagger规范的一个疏漏,我们应该如何做?非常感谢您的帮助。
注意:许多人可能建议在路由末尾附加操作,但我们希望避免这种情况,因为这意味着我们的端点不符合RESTful规范。我们希望像customers/1这样的格式,使用GET、POST、PUT属性派生CRUD操作,而不必追加类似于customers/add_customer_1或customers/add_customer_2的内容反映URL中的方法名称。