2014-09-19 152 views
0

我们有一个适用于我们网站的REST API。我们通过在端点添加或更新端点的发布版本前添加端点来对端点进行版本控制。例如ASP.Net MVC:截取路由并转发到不同的动作/路由

  • /V1 /服务A
  • /V2 /服务B
  • /V3 /服务-C

用这种方法,我们有我们的客户端代码调用的问题出到不同版本的端点。例如,一个页面可能会调用/ v3/service-c和/ v1/service-a。

我想设置它,这样我们的开发人员就可以通过在最终版本的端点前添加端点来访问最新版本的API。使用上面的例子,页面会调用到/ v3/service-c和/ v3/service-a,并且对于服务-a,请求将被转发到绑定到/ v1/service-a的动作,因为是/ v3之前的最新版服务。

我知道我可以手动在代码中手动添加路由,但管理不同版本的端点会很困难。

我知道如何枚举路由表中的版本并解析它们;这样一部分就解决了。然而,我不确定的是我如何去拦截路由,以便对/ v3/-service-a的调用可以被转发到我为/ v1/service-a设置的路由。

任何想法?

回答

10

试想一下,你声明你这样的路线:

 config.Routes.MapHttpRoute("defaultVersioned", "v{version}/{controller}/{id}", 
      new { id = RouteParameter.Optional }, new { version = @"\d+" }); 

     config.Routes.MapHttpRoute("default", "{controller}/{id}", 
      new { id = RouteParameter.Optional }); 

现在,您可以创建一个单独的版本不同的控制器,例如使用特定的命名约定:现在

public class FooController : ApiController {} 

public class FooV2Controller : ApiController {} 

public class FooV3Controller : ApiController {} 

,因为版本是部分你可以实现一个自定义控制器选择器,你可以在这里选择路径中的版本并根据它选择一个相关的控制器。

public class VersionAwareControllerSelector : DefaultHttpControllerSelector 
{ 
    public VersionAwareControllerSelector(HttpConfiguration configuration) : base(configuration) { } 

    public override string GetControllerName(HttpRequestMessage request) 
    { 
     var controllerName = base.GetControllerName(request); 
     var versionFinder = new VersionFinder(); 
     var version = versionFinder.GetVersionFromRequest(request); 

     if (version > 0) 
     { 
      return GetVersionedControllerName(request, controllerName, version); 
     } 

     return controllerName; 
    } 

    private string GetVersionedControllerName(HttpRequestMessage request, string baseControllerName, int version) 
    { 
     var versionControllerName = string.Format("{0}v{1}", baseControllerName, version); 
     HttpControllerDescriptor descriptor; 
     if (GetControllerMapping().TryGetValue(versionControllerName, out descriptor)) 
     { 
      return versionControllerName; 
     } 

     throw new HttpResponseException(request.CreateErrorResponse(
       HttpStatusCode.NotFound, 
       String.Format("No HTTP resource was found that matches the URI {0} and version number {1}", 
        request.RequestUri, version))); 
    } 
} 

此代码使用一个VersionFinder助手类,其可以被发现here

然后你只需要注册自定义选择:

config.Services.Replace(typeof(IHttpControllerSelector), new VersionAwareControllerSelector(config)); 

对于一个完整的例子 - have a look here on Github,它的的ASP.NET Web API 2食谱书的一部分。