【问题标题】:ASP.NET Web API 2 versioned routing with inheritance带有继承的 ASP.NET Web API 2 版本化路由
【发布时间】:2015-12-15 22:05:23
【问题描述】:

我一直在尝试在 Web API 2.2 (5.2.3) 中实现版本化路由,其中​​在为特定路由选择操作时,较新版本的控制器优先于以前的版本。

例如给定以下控制器类层次结构:

namespace MyApi.Controllers.V1 {
    public class FooController {
        protected IFooRepository Repo; // Assume Repo is injected via IoC

        [Route("{id:int:min(1)}")]
        public IFoo GetSingle(int id) {
            Repo.Single(new FooSearchOpts { Id = id });
        }

        public IEnumerable<IFoo> GetAll() {
            Repo.Search();
        }
    }
}

namespace MyApi.Controllers.V3 {
    public class FooController : V1.FooController {
        public IEnumerable<IFoo> Search(string type) {
            Repo.Search(new FooSearchOpts { Type = type });
        }
    }
}

namespace MyApi.Controllers.V4 {
    public class FooController : V3.FooController {
        public IEnumerable<IFoo> SearchV4(string type, string name) {
            Repo.Search(new FooSearchOpts {
                Type = type,
                Name = name
            });
        }
    }
}

namespace MyApi.Controllers.V5 {
    public class FooController : V4.FooController {
        /* nothing relevant */
    }
}

我可以通过创建一个自定义的IHttpControllerSelector 来使一些路由工作,该IHttpControllerSelector 从路由数据中读取{version}(例如GET /api/v*/foo/123 总是指向GetSingle)。

当不同版本的控制器有多个可能的路由时,就会出现问题。我需要请求GET /api/v*/foo来选择以下方法:

/api/v1/foo -> V1.FooController.GetAll
/api/v2/foo -> V1.FooController.GetAll
/api/v3/foo -> V3.FooController.Search
/api/v4/foo -> V4.FooController.SearchV4
/api/v5/foo -> V5.FooController.SearchV4

只需指定一个自定义控制器选择器就可以理解地抱怨重复/不明确的操作,但是当我指定一个自定义 IHttpActionSelector 时,我找不到任何方法来保留现有的操作选择逻辑。我真的需要手动重新实现所有方法名解析和参数检查的恶作剧,还是有办法利用现有逻辑?

很遗憾,我无法发布我已经拥有的所有内容,但主路由配置看起来像这样:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // VersionedRouteProvider specifies a global route prefix of "api/v{version}/{ctrl}"
        config.MapHttpAttributeRoutes(new VersionedRouteProvider());

        // VersionedControllerSelector uses {version} and {ctrl} to map out controllers
        var controllerSelector = new VersionedControllerSelector(config);
        config.Services.Replace(typeof(IHttpControllerSelector), controllerSelector);

        // VersionedActionSelector creates actions from controllers,
        // currently it would require iterating MethodInfos
        // and manually creating all HttpActionDescriptors
        // based on the methods' names and parameters
        config.Services.Replace(typeof(IHttpActionSelector), new VersionedActionSelector(controllerSelector));
    }
}

我已经考虑创建自定义 IDirectRouteProviderIDirectRouteFactory,但似乎我仍然需要自定义 IHttpActionSelector 来处理不明确的路线。

谢谢。

【问题讨论】:

    标签: c# asp.net .net asp.net-web-api asp.net-web-api2


    【解决方案1】:

    版本控制永远不应以这种方式工作,否则您可以禁用所有用户代码,因为他们将收到与以前不同的结果。版本控制应该使用属性路由 (api/v2/whatever) 来允许您的 api 的使用者根据他们的选择切换到较新的版本。

    [HttpGet, Route("api/v1/users")
    public IHttpActionResult UsersVersion1() {}
    
    [HttpGet, Route("api/v2/users")
    public IHttpActionResult UsersVersion2() {}
    

    【讨论】:

    • 用户仍然在 url 中明确指定 api 版本,就像在您的示例中一样,只是路由基于命名空间和类层次结构,而不必手动复制/粘贴版本之间可能相同的方法和必须使用路由属性手动注释所有内容。
    猜你喜欢
    • 2018-11-22
    • 2015-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-25
    • 2019-08-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多