设置AssumeDefaultVersionWhenUnspecified = true
是一个被高度滥用的功能。这只是为了促进向后兼容性。一旦你选择了 API 版本控制,所有的 API 控制器都有一些隐式或显式的 API 版本。假设版本提供了一种机制来处理“原始”、未命名的版本,否则会破坏不知道在请求中包含 API 版本的现有客户端。
“有什么方法可以告诉 Microsoft.AspNetCore.Mvc.Versioning,无论版本如何,都应该可以使用特定的方法?”
是的,但我不完全确定这就是你要找的。API 可以是版本中立的,这意味着它将接受任何和所有 API 版本,包括根本不接受。这对于某些类型的 API(例如/ping
运行状况检查或)很有用DELETE
,它们通常不会随时间而改变。这样的 API 可以用[ApiVersionNeutral]
. 这可以针对控制器上的所有 API 或特定操作。请注意,一旦您选择了这条路径,“只能有一个”。
没有您的设置的完整图片。您似乎正在向现有的一组 API 添加 API 版本控制。的主要目的之一DefaultApiVersion
是在没有其他信息可用时设置默认 API 版本。如果您没有应用任何 API 版本 - 例如,使用属性,那么这将是所有 API 的隐式 API 版本。这使您不必改造所有现有的控制器和代码。不太明显的是,一旦应用任何显式 API 版本,隐式规则就会被忽略。这确保了隐式版本可以日落。默认版本通常无关紧要。这只是一种指示最初的 API 版本是什么的方式。祖父时最相关在现有的 API 中。
鉴于您的配置:
// implicitly 3.0 because DefaultApiVersion = 3.0 and there
// are no explicit versions from attributes or conventions
[Route("customers/{customerId}/estates/{estateId:int}/meters/{meterNumber}-{installationId}/consumption/detail")]
public class CustomerController : ControllerBase
{
}
具有隐式版本控制的祖父控制器
// explicitly 2.0 due to attributes; DefaultApiVersion is ignored
[ApiVersion("2.0")]
[Route("v{version:apiVersion}/customers/{customerId}/estates/{estateId:int}/meters/{meterNumber}-{installationId}/consumption/detail")
[Route("customers/{customerId}/estates/{estateId:int}/meters/{meterNumber}-{installationId}/consumption/detail")]
public class CustomerController : ControllerBase
{
}
具有显式版本控制的控制器
除了支持向后兼容的原始 API 版本外,所有 API 版本都是显式和离散的;这是设计使然。模糊匹配不会以可预测的方式工作,因此精确匹配很重要。
您似乎在描述 API 版本交错 - 例如在单个控制器实现上实现的多个 API 版本。我想它可能看起来像:
[ApiVersion("2.0")]
[ApiVersion("3.0")]
[Route("v{version:apiVersion}/customers/{customerId}/estates/{estateId:int}/meters/{meterNumber}-{installationId}/consumption/detail")
[Route("customers/{customerId}/estates/{estateId:int}/meters/{meterNumber}-{installationId}/consumption/detail")]
public class CustomerController : ControllerBase
{
// implicitly maps to 2.0 from the controller, but does not
// match 3.0 because there is an explicit 3.0 mapping
[HttpGet]
public IActionResult Get(
string customerId,
int estateId,
string meterNumber,
string installationId ) => Ok();
// explicitly maps to 3.0 only
[MapToApiVersion("3.0")]
[HttpGet]
public IActionResult GetV3(
string customerId,
int estateId,
string meterNumber,
string installationId ) => Ok();
// explicitly maps to 3.0 only
// a 2.0 request produces 405
[MapToApiVersion("3.0")]
[HttpPut]
public IActionResult Put(
string customerId,
int estateId,
string meterNumber,
string installationId
[FromBody] ComsumptionDetail detail ) => Ok();
}
具有版本交错的控制器
DefaultApiVersion
只能应用单个隐式 API 版本。这意味着永远不会发生与它的交错。一旦您开始显式添加版本,您还必须开始包含隐式版本,因为没有其他方法可以指示不应再匹配隐式版本。
在路由定义和 API 版本映射方面,有几种方法可以用来最小化代码流失。VersionByNamespaceConvention是您可以应用的内置约定,它将从控制器类型的 .NET 命名空间派生 API 版本。这可以使添加、删除和组织控制器及其 API 版本变得非常容易。他们也可以使用交错,因为映射是相加的,但这可能会让人难以维护。您也可以定义自己的约定。
双路由注册是 URL 段版本控制的结果。它是最少 RESTful 的版本控制方法,因为它违反了统一接口约束。没有其他版本控制方法存在此问题。我建议不要浮动默认路由和 API 版本映射,因为您很可能会在某些时候破坏客户端。如果您只使用双路由来向后兼容原始 API 版本,那么您应该没问题。当您最终为未来的 API 版本创建新控制器时,模板中只有一个带有 API 版本的路由。