ASP.Net MVC:拦截路由并转发到不同的操作/路由

时间:2014-09-19 20:02:24

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

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

  • / v1 / service-a
  • / v2 / service-b
  • / V3 /服务-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设置的路由。 / p>

有什么想法吗?

1 个答案:

答案 0 :(得分:11)

想象一下,你宣布你的路线是这样的:

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