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

Fra*_*rio 1 asp.net-mvc-routing asp.net-web-api

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

  • / V1 /服务一个
  • / V2 /服务-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设置的路由.

有任何想法吗?

Fil*_*p W 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 });
Run Code Online (Sandbox Code Playgroud)

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

public class FooController : ApiController {}

public class FooV2Controller : ApiController {}

public class FooV3Controller : ApiController {}
Run Code Online (Sandbox Code Playgroud)

现在,由于版本是您的路线的一部分,您可以实现自定义控制器选择器,您可以从路径中选择版本并根据该选择相应的控制器.

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)));
    }
}
Run Code Online (Sandbox Code Playgroud)

此代码使用VersionFinder辅助类,可在此处找到.

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

  config.Services.Replace(typeof(IHttpControllerSelector), new VersionAwareControllerSelector(config));
Run Code Online (Sandbox Code Playgroud)

有关完整示例 - 请查看Github,它是ASP.NET Web API 2 Recipes一书的一部分.