处理 API 版本控制的另一种方法是为每个 API 版本实际使用不同版本的控制器,这样您就不需要在每个操作方法中检查每个版本号。每个控制器仅适用于 API 的一个版本。
对我来说,它更清洁(IMO)在路由时间而不是操作时间处理版本控制。您可以使用路由约束来检查版本号。
在下面的示例中,控制器 V10 和 V20 只有在路由约束通过时才能被路由到 - 即标头存在,如果没有标头则为默认值(即 v2):
routes.MapRoute(
"EmployeeListingv1",
"employees",
new { controller = "V10Employees", action = "Index" }, // Parameter defaults
new { ApiV = new ApiVersionConstraint(ApiVersion.Version10) }
);
routes.MapRoute(
"EmployeeListingv2",
"employees",
new { controller = "V20Employees", action = "Index" }, // Parameter defaults
new { ApiV = new ApiVersionConstraint(ApiVersion.Version20) }
);
您可以使用查询字符串来传递您当前正在执行的版本,然后更改为路由约束,但是我发现在请求中使用可选标头更容易维护。(它也更“RESTful”而不涉及整个辩论)。没有标题意味着 API 的默认(最新)版本。
示例 API 版本约束:
/// <summary>
/// Enable routing of requests to controllers based on the
/// API version contained in the header.
/// </summary>
public class ApiVersionConstraint : IRouteConstraint
{
const string VersionHeader = "X-MY-API-NAME-HERE-VERSION";
private ApiVersion _version = ApiVersion.Unsupported;
public ApiVersionConstraint(ApiVersion version)
{
this._version = version;
}
#region IRouteConstraint Members
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
string vers = string.Empty;
if (httpContext.Request.Headers[VersionHeader] != null)
{
vers = httpContext.Request.Headers[VersionHeader];
}
else
{
vers = "2.0"; // set default here.
}
ApiVersion fromHeader = ApiVersion.Unsupported;
switch (vers)
{
case "1.0":
{
fromHeader = ApiVersion.Version10;
break;
}
case "2.0":
{
fromHeader = ApiVersion.Version20;
break;
}
default:
{
fromHeader = ApiVersion.Unsupported;
break;
}
}
return fromHeader == _version;
}
#endregion
}