带有继承的 Web API 版本控制

Posted

技术标签:

【中文标题】带有继承的 Web API 版本控制【英文标题】:Web API Versioning With Inheritance 【发布时间】:2018-11-22 02:06:30 【问题描述】:

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

[ApiVersion("1.0")]
[RoutePrefix("api/vversion: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/vversion: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 的值”

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

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

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();

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

【问题讨论】:

【参考方案1】:

您需要做的是覆盖DefaultDirectRoutePrivider 以允许路由继承:

public class WebApiCustomDirectRouteProvider : DefaultDirectRouteProvider 
    protected override IReadOnlyList<IDirectRouteFactory>
        GetActionRouteFactories(HttpActionDescriptor actionDescriptor) 
        // inherit route attributes decorated on base class controller's actions
        return actionDescriptor.GetCustomAttributes<IDirectRouteFactory>(inherit: true);
    

完成后,您需要在 Web api 配置中配置它以及自定义路由约束

public static void Register(HttpConfiguration config) 
    var constraintResolver = new DefaultInlineConstraintResolver() 
        ConstraintMap = ["apiVersion"] = typeof(ApiVersionRouteConstraint)
    ;
    var directRouteProvider = new WebApiCustomDirectRouteProvider();
    // Attribute routing. (with inheritance)
    config.MapHttpAttributeRoutes(constraintResolver, directRouteProvider);
    config.AddApiVersioning(_ =>  _.AssumeDefaultVersionWhenUnspecified = true; );

所以现在继承值控制器现在将拥有派生控制器中可用的基本路由

出于演示目的

[ApiVersion("1.0")]
[RoutePrefix("api/vversion:apiVersion/Values")]
[ControllerName("Values")]
public class ValuesController : ApiController 

    [HttpGet]
    [Route("")] // GET api/v1.0/values
    public virtual IHttpActionResult Get() 
        return Ok(new string[]  "value1", "value2" );
    

    [HttpGet]
    [Route("id:int")] // GET api/v1.0/values/5
    public virtual IHttpActionResult Get(int id) 
        return Ok("value from 1");
    


[ApiVersion("2.0")]
[RoutePrefix("api/vversion:apiVersion/Values")]
[ControllerName("Values")]
public class Values2Controller : ValuesController 

    //Will have inherited GET "api/v2.0/Values" route

    // GET api/v2.0/values/5 (Route also inherited from base controller)
    public override IHttpActionResult Get(int id) 
        return Ok("value from 2");
    
 

您会注意到子节点中的路由并未用于被覆盖的操作,因为它也将从基本控制器继承。

【讨论】:

以上是关于带有继承的 Web API 版本控制的主要内容,如果未能解决你的问题,请参考以下文章

带有 IHttpControllerSelector 的 AttributeRouting - Api 版本控制

Java Web学习总结(43)—— Restful API 版本控制

Java Web学习总结(43)—— Restful API 版本控制

Service Fabric Web API 版本控制问题

web api 多版本控制重要的两个类

Web api dotnet core 中的 Api 版本控制错误的自定义错误响应