具有继承性的 Web API 版本控制

我试图让 Web API 版本控制与继承的类一起工作。我正在使用股票Values控制器的两个非常简单的变体。


[ApiVersion("1.0")]

[RoutePrefix("api/v{version:apiVersion}/Values")]

[ControllerName("Values")]

public class ValuesController : ApiController

{

    // GET api/values

    [Route("")]

    public IEnumerable<string> Get()

    {

        return new string[] { "value1", "value2" };

    }


    // GET api/values/5

    [Route("{id:int}")]

    public virtual string Get(int id)

    {

        return "value from 1";

    }

}


[ApiVersion("2.0")]

[RoutePrefix("api/v{version:apiVersion}/Values")]

[ControllerName("Values")]

public class Values2Controller : ValuesController

{

    //Want to use the method in the base class

    //public IEnumerable<string> Get()

    //{

    //    return new string[] { "value2-1", "value2-2" };

    // }


    [Route("{id:int}")]

    // GET api/values/5

    public new string Get(int id)

    {

        return "value from 2";

    }

我的启动配置也非常简单。


public static void Register(HttpConfiguration config)

{

    var constraintResolver = new DefaultInlineConstraintResolver()

    {

        ConstraintMap = {["apiVersion"] = typeof(ApiVersionRouteConstraint)}

    };

    config.MapHttpAttributeRoutes(constraintResolver);

    config.AddApiVersioning(o => { o.AssumeDefaultVersionWhenUnspecified = true; });

}

未覆盖的路由完全按照我的预期工作 http://localhost:32623/api/v1.0/Values/12->“来自 1 的值” http://localhost:32623/api/v2.0/Values/12->“来自 2 的值”


调用默认Get路由的 v1 http://localhost:32623/api/v1.0/Values -> Value1, Value2


但是在子控制器上尝试相同的路由会导致错误。


http://localhost:32623/api/v2.0/Values


<Message>

The HTTP resource that matches the request URI 'http://localhost:32623/api/v2.0/Values' does not support the API version '2.0'.

</Message>

<InnerError>

<Message>

No route providing a controller name with API version '2.0' was found to match request URI 'http://localhost:32623/api/v2.0/Values'.

</Message>

</InnerError>

错误消息表明被覆盖的成员需要“1.0”路由,我可以在子类中使用这样的方法解决这个问题。


[Route("")]

public override IEnumerable<string> Get()

{

    return base.Get();

}

但这在更大的应用程序中似乎不太理想。有没有办法让这项工作按照我想要的方式工作,没有这些“空”覆盖?


陪伴而非守候
浏览 181回答 1
1回答

喵喵时光机

您需要做的是覆盖DefaultDirectRoutePrivider以允许路由继承:public class WebApiCustomDirectRouteProvider : DefaultDirectRouteProvider {&nbsp; &nbsp; protected override IReadOnlyList<IDirectRouteFactory>&nbsp; &nbsp; &nbsp; &nbsp; GetActionRouteFactories(HttpActionDescriptor actionDescriptor) {&nbsp; &nbsp; &nbsp; &nbsp; // inherit route attributes decorated on base class controller's actions&nbsp; &nbsp; &nbsp; &nbsp; return actionDescriptor.GetCustomAttributes<IDirectRouteFactory>(inherit: true);&nbsp; &nbsp; }}完成后,您将需要在您的 web api 配置中配置它以及自定义路由约束public static void Register(HttpConfiguration config) {&nbsp; &nbsp; var constraintResolver = new DefaultInlineConstraintResolver() {&nbsp; &nbsp; &nbsp; &nbsp; ConstraintMap = {["apiVersion"] = typeof(ApiVersionRouteConstraint)}&nbsp; &nbsp; };&nbsp; &nbsp; var directRouteProvider = new WebApiCustomDirectRouteProvider();&nbsp; &nbsp; // Attribute routing. (with inheritance)&nbsp; &nbsp; config.MapHttpAttributeRoutes(constraintResolver, directRouteProvider);&nbsp; &nbsp; config.AddApiVersioning(_ => { _.AssumeDefaultVersionWhenUnspecified = true; });}所以现在继承值控制器现在将具有派生控制器中可用的基本路由用于演示目的[ApiVersion("1.0")][RoutePrefix("api/v{version:apiVersion}/Values")][ControllerName("Values")]public class ValuesController : ApiController {&nbsp; &nbsp; [HttpGet]&nbsp; &nbsp; [Route("")] // GET api/v1.0/values&nbsp; &nbsp; public virtual IHttpActionResult Get() {&nbsp; &nbsp; &nbsp; &nbsp; return Ok(new string[] { "value1", "value2" });&nbsp; &nbsp; }&nbsp; &nbsp; [HttpGet]&nbsp; &nbsp; [Route("{id:int}")] // GET api/v1.0/values/5&nbsp; &nbsp; public virtual IHttpActionResult Get(int id) {&nbsp; &nbsp; &nbsp; &nbsp; return Ok("value from 1");&nbsp; &nbsp; }}[ApiVersion("2.0")][RoutePrefix("api/v{version:apiVersion}/Values")][ControllerName("Values")]public class Values2Controller : ValuesController {&nbsp; &nbsp; //Will have inherited GET "api/v2.0/Values" route&nbsp; &nbsp; // GET api/v2.0/values/5 (Route also inherited from base controller)&nbsp; &nbsp; public override IHttpActionResult Get(int id) {&nbsp; &nbsp; &nbsp; &nbsp; return Ok("value from 2");&nbsp; &nbsp; }}&nbsp;您会注意到子级中的路由并未用于覆盖的操作,因为它也将从基本控制器继承。
打开App,查看更多内容
随时随地看视频慕课网APP