我最初的问题是我正在寻找在Restful API中进行版本控制的最佳实践。没有多少人谈论这个问题,没有一个好的答案,或者我目前无法确切找到解决方案。
(1)首先,我想为每个版本http://domain.com/API/ {version}使用Tag
或Branch
。因此,如果发布了新的API,我将其Tag
导出并发布到相应的URL中,但是似乎很难在一个Web应用程序中混合不同版本的源代码。
(2)然后我正在考虑使用这种方式,一个控制器用于一个版本:
(就像这个问题Versioning of REST API Built With ASP.NET MVC 3 - Best Practices)http://domain.com/API/1.0/{AnAction} => will go to APIV1Controller.{AnAction}
http://domain.com/API/2.0/{AnAction} => will go to APIV2Controller.{AnAction}
但它需要为每个版本写一条路由。
(3)第三种方式是从PayPal API中获得想法,即版本不在URL中,而在POST参数中。因此,URL固定为http://domain.com/API/
,但用户必须指定Version
参数以具有"1.0"
或"2.0"
。
解决方案:(2)对我来说还可以,目前我使用这种方式,但是我想将(2)和(3)混合使用,所以我有一个APIController,该APIController仅具有一个Index操作来检查此Version
参数并将请求传输到相应的控制器,然后执行APIV1Controller。{AnAction}或APIV2Controller。{AnAction}操作。
在Google搜索和Stackoverflowing有关如何转移,调用或调用另一个控制器和操作而不进行重定向之后。似乎没有好的答案和良好的实践。有人通过简单地创建控制器的新实例来回答.NET MVC Call method on different controller。突然我想到了reroute
的想法!
问题:
是否可以在不重定向的情况下从另一个动作中reroute
另一个控制器和另一个动作,该怎么做?
还是一个特定的问题,当用户向http://domain.com/API/{AnAction}
请求Version="2.0"
时,如何将reroute
从APIController.Index
转换为APIV2Controller.{AnAction}
?
我没有使用IoC。
最佳答案
这可以通过路由约束来完成。首先实现IRouteConstraint
:
public class RequestParameterConstraint : IRouteConstraint
{
public string ParameterName { get; private set; }
public string ParameterValue { get; private set; }
public RequestParameterConstraint(string parameter, string value)
{
ParameterName = parameter;
ParameterValue = value;
}
public bool Match(HttpContextBase httpContext, Route route, string parameterName,
RouteValueDictionary values, RouteDirection routeDirection)
{
var value = httpContext.Request[ParameterName] ?? "";
return value.Equals(ParameterValue);
}
}
然后注册路线:
routes.MapRoute(
"Version10",
"API/{action}/{id}",
new { controller = "APIV1", action = "Index", id = UrlParameter.Optional },
new { header = new RequestParameterConstraint("Version", "1.0") }
);
routes.MapRoute(
"Version20",
"API/{action}/{id}",
new { controller = "APIV2", action = "Index", id = UrlParameter.Optional },
new { header = new RequestParameterConstraint("Version", "2.0") }
);
就这样。这将达到目的。