【问题标题】:ASP.Net MVC: Intercepting routing and forwarding to different actions/routesASP.Net MVC:拦截路由并转发到不同的动作/路由
【发布时间】:2014-09-19 20:02:23
【问题描述】:

我们的网站有一个 REST API。我们通过在端点添加或更新端点的发布版本前缀来对端点进行版本控制。例如

  • /v1/service-a
  • /v2/service-b
  • /v3/service-c

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

我想对其进行设置,以便我们的开发人员只需在端点前加上最新版本的端点即可访问最新版本的 API。使用上面的示例,页面将改为调用 /v3/service-c 和 /v3/service-a,对于 service-a,请求将被转发到绑定到 /v1/service-a 的操作,因为是 /v3 之前服务的最新版本。

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

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

有什么想法吗?

【问题讨论】:

    标签: asp.net-web-api asp.net-mvc-routing


    【解决方案1】:

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

            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 食谱书的一部分。

    【讨论】:

      猜你喜欢
      • 2011-11-22
      • 1970-01-01
      • 2015-10-11
      • 2018-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多