APIのバージョン管理を処理する別の方法は、APIバージョンごとに実際に異なるバージョンのコントローラーを用意することです。これにより、各アクションメソッドのすべてのバージョン番号をすべてチェックする必要がなくなります。各コントローラーは、APIの1つのバージョンにのみ適用できます。
私にとってのそのクリーナー(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
}