Web API 继承的版本控制
Web API Versioning With Inheritance
我正在尝试让 Web API 版本控制与继承的 class 一起工作。我正在使用库存 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
-> "value from 1"
http://localhost:32623/api/v2.0/Values/12
-> "value from 2"
调用默认Get
路由的v1
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”路由,我可以在子 class.
中使用这样的方法解决这个问题
[Route("")]
public override IEnumerable<string> Get()
{
return base.Get();
}
但这在较大的应用程序中似乎不太理想。如果没有这些 "empty" 覆盖,有没有办法按照我想要的方式进行这项工作?
您需要做的是覆盖 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);
}
}
完成后,您需要在您的网络 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/v{version: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/v{version: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 版本控制与继承的 class 一起工作。我正在使用库存 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
-> "value from 1"
http://localhost:32623/api/v2.0/Values/12
-> "value from 2"
调用默认Get
路由的v1
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”路由,我可以在子 class.
中使用这样的方法解决这个问题[Route("")]
public override IEnumerable<string> Get()
{
return base.Get();
}
但这在较大的应用程序中似乎不太理想。如果没有这些 "empty" 覆盖,有没有办法按照我想要的方式进行这项工作?
您需要做的是覆盖 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);
}
}
完成后,您需要在您的网络 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/v{version: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/v{version: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");
}
}
您会注意到子级中的路由未用于覆盖操作,因为它也将从基本控制器继承。