我正在尝试使用 Asp Versioning Mvc ApiExplorer 库创建版本控制的 swagger。
我遵循了基本指南文档并应用了操作过滤器,但即使我指定了默认的api版本,如果存在具有“ApiVersion”属性的api,则不会为没有该属性的api生成。 (如果只有一个没有属性的API,则会使用默认版本创建)。
如果没有属性的 API 总是可以用默认版本生成,那就太好了。
这是我的操作过滤器。
public void Apply( OpenApiOperation operation, OperationFilterContext context )
{
var apiDescription = context.ApiDescription;
operation.Deprecated |= apiDescription.IsDeprecated();
foreach ( var responseType in context.ApiDescription.SupportedResponseTypes )
{
var responseKey = responseType.IsDefaultResponse
? "default"
: responseType.StatusCode.ToString();
var response = operation.Responses[responseKey];
foreach ( var contentType in response.Content.Keys )
{
if ( !responseType.ApiResponseFormats.Any( x => x.MediaType == contentType ) )
{
response.Content.Remove( contentType );
}
}
}
if ( operation.Parameters == null )
{
return;
}
foreach ( var parameter in operation.Parameters )
{
var description = apiDescription.ParameterDescriptions
.First( p => p.Name == parameter.Name );
parameter.Description ??= description.ModelMetadata?.Description;
if ( parameter.Schema.Default == null && description.DefaultValue != null )
{
var json = JsonSerializer.Serialize(
description.DefaultValue,
description.ModelMetadata.ModelType );
parameter.Schema.Default = OpenApiAnyFactory.CreateFromJson( json );
}
parameter.Required |= description.IsRequired;
}
}
控制器
[ApiController]
[ApiExplorerSettings(GroupName = "Version")]
[Route("version")]
public class VersionController : ControllerBase
{
/// <summary>
/// For Testing. (i want this api document, but not generated)
/// </summary>
/// <response code="200">Product retrieved</response>
[HttpGet]
public async Task<IActionResult> Version1Get()
{
return Ok("version1.0 response");
}
/// <summary>
/// Fot Testing 1.2.
/// </summary>
/// <response code="200">Product retrieved</response>
[HttpGet]
[ApiVersion(1.2)]
public async Task<IActionResult> Version2Get()
{
return Ok("version1.2 response");
}
}
版本控制设置
{
options.ApiVersionReader = new HeaderApiVersionReader("x-ms-version");
options.DefaultApiVersion = new ApiVersion(1, 0);
options.ReportApiVersions = true;
options.AssumeDefaultVersionWhenUnspecified = true;
}).AddMvc().AddApiExplorer(
options =>
{
options.GroupNameFormat = "VV";
options.FormatGroupName = (group, version) => $"{group} - {version}";
options.DefaultApiVersion = new ApiVersion(1, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
} );
这个设计是有意为之的。 API 版本控制要求 API 版本明确。如果您采用了 API 版本控制,然后需要更改应用程序以保持正常运行,那将是痛苦,并且可能会阻碍采用。
每个 API 都有一些版本,即使它没有正式声明。启用 API 版本控制后,就会出现“默认版本”。你可以称呼或标记你喜欢的东西,但它总是在那里。现在,它才具有正式的价值。 相反,想象一下您达到了 V3 或 V4,并且您想要取消原始 V1 版本。如果始终包含
defaultAPI 版本,那么您将无法删除它。仅当没有其他属性或约定定义任何 API 版本时,default API 版本才适用。一旦开始定义其他 API 版本,您就需要包含原始 API 版本,以表达您打算保留该版本而不是删除它的意图。仅当您在同一 API 上交错多个版本时,才会出现此问题。 如果您想在所有控制器上隐式包含默认 API 版本,那么最好的方法是使用自定义
约定。
internal sealed class DefaultApiVersionConvention : IControllerConvention
{
private readonly ApiVersion defaultApiVersion;
public DefaultApiVersionConvention() : this(new ApiVersion(1.0)) { }
public DefaultApiVersionConvention(ApiVersion defaultApiVersion)
=> this.defaultApiVersion = defaultApiVersion;
public bool Apply(
IControllerConventionBuilder builder,
ControllerModel controller) =>
builder.HasApiVersion(this.defaultApiVersion);
}
然后您可以将其连接到配置中:
builder.Services
.AddApiVersioning(
options =>
{
// an explicit value is ok, but...
// 1.0 == ApiVersion.Default == default value
options.DefaultApiVersion = new ApiVersion(1, 0);
options.ApiVersionReader = new HeaderApiVersionReader("x-ms-version");
options.ReportApiVersions = true;
options.AssumeDefaultVersionWhenUnspecified = true;
})
.AddMvc(options => options.Conventions.Add(new DefaultApiVersionConvention()))
.AddApiExplorer(
options =>
{
options.GroupNameFormat = "VV";
options.FormatGroupName = (group, version) => $"{group} - {version}";
});
这将使您的 OpenAPI(例如 Swagger)配置的其余部分无需任何额外更改即可工作。
Sidebar:您可以将
1.0
明确指定,但这是默认值,相当于。虽然您ApiVersion.Default
可以也可以在 API Explorer 中配置这些值,但您不应该。它们将自动派生为ApiVersioningOptions
中的相同配置值。