刚刚意识到我对 ASP.NET Core 6 Web API 版本控制的理解是错误的。
这是我的控制器:
[ApiVersion("1.0")]
[ApiController]
[Authorize]
public class FundController
{
[MapToApiVersion("1.0")]
[Route("/Fund/v{version:apiVersion}/delta")]
public async Task<List<PortfolioHolding<Holding>>> Delta([FromQuery] Request dataModel)
{
}
}
我想要的是支持路线
/Fund/v1.0/delta
和/Fund/delta
,当消费者未提供版本控制时(例如调用/Fund/delta
),将使用默认版本。
所以我像这样配置了版本控制。但是,当我调用
/Fund/delta
时,我收到 http 404 错误。
但是
/Fund/v1.0/delta
会击中正确的控制器。
我做错了什么?
services.AddApiVersioning(option =>
{
option.DefaultApiVersion = new ApiVersion(1, 0);
option.AssumeDefaultVersionWhenUnspecified = true;
option.ReportApiVersions = true;
});
问题是你没有在控制器中指定路由。
您应该添加默认路由以及格式化版本路由。然后,您应该确保您的端点具有 MapToApiVersion 属性中指定的版本。
以下是控制器的代码示例:
[ApiVersion("1.0")]
[ApiVersion("2.0")]
[Route("[controller]")]
[Route("[controller]/v{version:apiVersion}")]
public class FundController : ControllerBase
{
[MapToApiVersion("1.0")]
[Route("delta")]
[HttpGet]
public async Task<List<PortfolioHolding<Holding>>> DeltaV1([FromQuery] Request dataModel)
{
}
[MapToApiVersion("2.0")]
[Route("delta")]
[HttpGet]
public async Task<List<PortfolioHolding<Holding>>> DeltaV2([FromQuery]
Request dataModel)
{
}
}
另一种无需在每个控制器上都有
[Route("api/[controller")]
的方法是实现并使用 Asp.Versioning.Conventions 中的 IControllerConvention
internal class DefaultRouteHandler : IControllerConvention
{
public bool Apply(IControllerConventionBuilder builder, ControllerModel controller)
{
var attributeModel = new AttributeRouteModel();
var selectorModel = new SelectorModel();
attributeModel.Template = "api/[controller]";
selectorModel.AttributeRouteModel = attributeModel;
controller.Selectors.Add(selectorModel);
return true;
}
}
然后在你的主要...
services.AddApiVersioning(option =>
{
option.DefaultApiVersion = new ApiVersion(1, 0);
option.AssumeDefaultVersionWhenUnspecified = true;
option.ReportApiVersions = true;
})
.AddMvc(option => option.Conventions.Add(new DefaultRouteHandler()));
为了防止 Swagger 显示重复的(版本+默认)路由,您可以执行类似的操作
builder.Services.AddSwaggerGen(x =>
{
x.DocInclusionPredicate((v, d) => d.RelativePath.Contains($"/{v}/", StringComparison.OrdinalIgnoreCase));
});
通常,这样做很容易。这种方法的缺点是您需要使用此属性手动更改 API 的“默认”版本
[ApiController]
[Route("api/v1/[controller]")]
[Route("api/[controller]")]
[ApiVersion("1.0")]