ASP.NET WebAPI 2 版本控制 POST with id
ASP.NET WebAPI 2 Versioning POST with id
我正在尝试在现有的高效 WebAPI 2 应用程序中实施 'Microsoft.AspNet.WebApi.Versioning' nuget,以支持新设计的 'v2' 控制器。
到目前为止,大多数控制器都能正常工作,但现在我 运行 遇到了一些 POST 控制器的问题。
示例代码:
using Microsoft.Web.Http;
using System.Web.Http;
namespace ApplicationApi.Controllers
{
[ApiVersion("1.0")]
[Route("api/version")]
public class VersionController : ApiController
{
//Works
[HttpGet]
public IHttpActionResult Get()
{
return Ok(true);
}
//Throws HTTP 405 - The requested resource with API version '1.0' does not support HTTP method 'POST'.
[HttpPost]
public IHttpActionResult Post(int id, [FromBody]dynamic value)
{
return Ok(true);
}
//Works
[HttpPost]
public IHttpActionResult Post([FromBody]dynamic value)
{
return Ok(true);
}
}
}
所有 POST 方法都没有额外的 {id} 工作。但是由于我们长期以来有大量的老客户,所以我必须保持旧版本和 运行,并且不能选择删除旧控制器中的 {id}。在新控制器中不需要 {id}。
WebAPI 配置
var constraintResolver = new DefaultInlineConstraintResolver()
{
ConstraintMap =
{
["apiVersion"] = typeof( ApiVersionRouteConstraint )
}
};
config.MapHttpAttributeRoutes(constraintResolver);
config.AddApiVersioning(options =>
{
options.AssumeDefaultVersionWhenUnspecified = true;
});
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
知道我做错了什么或如何解决这个问题吗?
问题是你有 2 个 post 方法,api 不知道如何 identify/generate 资源名称。
您需要做的是添加一个自定义的重复方法名的资源名。
因此,如果我们以您的示例为例,您可以将资源添加到抛出异常的资源并保留另一个资源,或者为它们提供唯一的资源名称。
例如 [HttpPost("id")]
.
为了确认这一点,我用你的代码做了一个测试项目,为此我使用了 swagger,但它失败了。现在,当我将 id
添加到 post 方法之一时,如下所示:
[HttpPost("id")]
public IActionResult Post(int id, [FromBody]dynamic value)
{
return Ok(true);
}
[HttpPost]
public IActionResult Post([FromBody]dynamic value)
{
return Ok(true);
}
然后它与以下输出一起工作:
补充主要答案
在您的代码中,您允许通过在方法
中添加 int id
来获取参数
Post(int id, [FromBody]dynamic value)
如果你真的不想使用参数,那么你可以传递给你自定义的对象 class 并做一些类似的事情,而不是测试它:
Post([FromBody]MyCustomObjectClass data)
还有你MyCustomerObjectClass
:
class MyCustomObjectClass {
public int? Id { get; set; }
public dynamic Value { get; set; }
}
你不需要2个post方法,你可以只有一个,Id可以是可选的。
只是为了不让您感到困惑。我不好,我在 post 中使用了 id 作为命名约定,例如 [HttpPost("id")]
,它与您的方法 Id 参数无关。 id
在这种情况下只是资源的名称,它对操作没有影响。所以你可以根据你的逻辑称呼它 [HttpPost("post1")]
和 [HttpPost("post2")]
.
最后一个建议,使用动态测试并在短时间内启动 api 很好,但我总是使用静态类型对象。
我强烈建议您看看 this。
问题与版本无关
带有 id
参数的方法不起作用的原因是您有 冲突路由:
[Route("api/version")]
和
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
对于名为 Version
且具有 Route("api/version")
属性的控制器,您只能具有任一属性路由,或 常规路由(MVC / WebAPI 路由),但是你不能两者兼得。
在您的情况下,属性路由覆盖了 MVC 路由,因此 api/version/{id}
不再存在。但是 api/version?id
仍然有效,因为它是由属性路由寻址的。
要解决该问题,您可以将控制器上的属性路由更改为 RoutePrefix
而不是 Route
,并使用 Route
如有必要,在每个操作上使用相对路径。
necessary表示您有常规路由无法寻址的路由。
[ApiVersion("1.0")]
[RoutePrefix("api/version")]
public class VersionController : ApiController
{
[HttpPost]
public IHttpActionResult Post([FromBody] dynamic value)
{
return Ok();
}
[HttpPost]
public IHttpActionResult Post(int id, [FromBody] dynamic value)
{
return Ok(1);
}
}
尝试
[ApiVersion("1.0")]
public class VersionController : ApiController
{
//Works
[HttpGet]
[Route("api/version")]
public IHttpActionResult Get()
{
return Ok(true);
}
//Throws HTTP 405 - The requested resource with API version '1.0' does not support HTTP method 'POST'.
[HttpPost]
[Route("api/version/{id}")]
public IHttpActionResult Post([FromUri]int id, [FromBody]dynamic value)
{
return Ok(true);
}
//Works
[HttpPost]
[Route("api/version")]
public IHttpActionResult Post([FromBody]dynamic value)
{
return Ok(true);
}
}
或
[ApiVersion("1.0")]
[RoutePrefix("api/version/")]
public class VersionController : ApiController
{
//Works
[HttpGet]
public IHttpActionResult Get()
{
return Ok(true);
}
//Throws HTTP 405 - The requested resource with API version '1.0' does not support HTTP method 'POST'.
[HttpPost]
[Route("{id}")]
public IHttpActionResult Post([FromUri]int id, [FromBody]dynamic value)
{
return Ok(true);
}
//Works
[HttpPost]
public IHttpActionResult Post([FromBody]dynamic value)
{
return Ok(true);
}
}
我正在尝试在现有的高效 WebAPI 2 应用程序中实施 'Microsoft.AspNet.WebApi.Versioning' nuget,以支持新设计的 'v2' 控制器。
到目前为止,大多数控制器都能正常工作,但现在我 运行 遇到了一些 POST 控制器的问题。
示例代码:
using Microsoft.Web.Http;
using System.Web.Http;
namespace ApplicationApi.Controllers
{
[ApiVersion("1.0")]
[Route("api/version")]
public class VersionController : ApiController
{
//Works
[HttpGet]
public IHttpActionResult Get()
{
return Ok(true);
}
//Throws HTTP 405 - The requested resource with API version '1.0' does not support HTTP method 'POST'.
[HttpPost]
public IHttpActionResult Post(int id, [FromBody]dynamic value)
{
return Ok(true);
}
//Works
[HttpPost]
public IHttpActionResult Post([FromBody]dynamic value)
{
return Ok(true);
}
}
}
所有 POST 方法都没有额外的 {id} 工作。但是由于我们长期以来有大量的老客户,所以我必须保持旧版本和 运行,并且不能选择删除旧控制器中的 {id}。在新控制器中不需要 {id}。
WebAPI 配置
var constraintResolver = new DefaultInlineConstraintResolver()
{
ConstraintMap =
{
["apiVersion"] = typeof( ApiVersionRouteConstraint )
}
};
config.MapHttpAttributeRoutes(constraintResolver);
config.AddApiVersioning(options =>
{
options.AssumeDefaultVersionWhenUnspecified = true;
});
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
知道我做错了什么或如何解决这个问题吗?
问题是你有 2 个 post 方法,api 不知道如何 identify/generate 资源名称。
您需要做的是添加一个自定义的重复方法名的资源名。
因此,如果我们以您的示例为例,您可以将资源添加到抛出异常的资源并保留另一个资源,或者为它们提供唯一的资源名称。
例如 [HttpPost("id")]
.
为了确认这一点,我用你的代码做了一个测试项目,为此我使用了 swagger,但它失败了。现在,当我将 id
添加到 post 方法之一时,如下所示:
[HttpPost("id")]
public IActionResult Post(int id, [FromBody]dynamic value)
{
return Ok(true);
}
[HttpPost]
public IActionResult Post([FromBody]dynamic value)
{
return Ok(true);
}
然后它与以下输出一起工作:
补充主要答案 在您的代码中,您允许通过在方法
中添加int id
来获取参数
Post(int id, [FromBody]dynamic value)
如果你真的不想使用参数,那么你可以传递给你自定义的对象 class 并做一些类似的事情,而不是测试它:
Post([FromBody]MyCustomObjectClass data)
还有你MyCustomerObjectClass
:
class MyCustomObjectClass {
public int? Id { get; set; }
public dynamic Value { get; set; }
}
你不需要2个post方法,你可以只有一个,Id可以是可选的。
只是为了不让您感到困惑。我不好,我在 post 中使用了 id 作为命名约定,例如 [HttpPost("id")]
,它与您的方法 Id 参数无关。 id
在这种情况下只是资源的名称,它对操作没有影响。所以你可以根据你的逻辑称呼它 [HttpPost("post1")]
和 [HttpPost("post2")]
.
最后一个建议,使用动态测试并在短时间内启动 api 很好,但我总是使用静态类型对象。
我强烈建议您看看 this。
问题与版本无关
带有 id
参数的方法不起作用的原因是您有 冲突路由:
[Route("api/version")]
和
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
对于名为 Version
且具有 Route("api/version")
属性的控制器,您只能具有任一属性路由,或 常规路由(MVC / WebAPI 路由),但是你不能两者兼得。
在您的情况下,属性路由覆盖了 MVC 路由,因此 api/version/{id}
不再存在。但是 api/version?id
仍然有效,因为它是由属性路由寻址的。
要解决该问题,您可以将控制器上的属性路由更改为 RoutePrefix
而不是 Route
,并使用 Route
如有必要,在每个操作上使用相对路径。
necessary表示您有常规路由无法寻址的路由。
[ApiVersion("1.0")]
[RoutePrefix("api/version")]
public class VersionController : ApiController
{
[HttpPost]
public IHttpActionResult Post([FromBody] dynamic value)
{
return Ok();
}
[HttpPost]
public IHttpActionResult Post(int id, [FromBody] dynamic value)
{
return Ok(1);
}
}
尝试
[ApiVersion("1.0")]
public class VersionController : ApiController
{
//Works
[HttpGet]
[Route("api/version")]
public IHttpActionResult Get()
{
return Ok(true);
}
//Throws HTTP 405 - The requested resource with API version '1.0' does not support HTTP method 'POST'.
[HttpPost]
[Route("api/version/{id}")]
public IHttpActionResult Post([FromUri]int id, [FromBody]dynamic value)
{
return Ok(true);
}
//Works
[HttpPost]
[Route("api/version")]
public IHttpActionResult Post([FromBody]dynamic value)
{
return Ok(true);
}
}
或
[ApiVersion("1.0")]
[RoutePrefix("api/version/")]
public class VersionController : ApiController
{
//Works
[HttpGet]
public IHttpActionResult Get()
{
return Ok(true);
}
//Throws HTTP 405 - The requested resource with API version '1.0' does not support HTTP method 'POST'.
[HttpPost]
[Route("{id}")]
public IHttpActionResult Post([FromUri]int id, [FromBody]dynamic value)
{
return Ok(true);
}
//Works
[HttpPost]
public IHttpActionResult Post([FromBody]dynamic value)
{
return Ok(true);
}
}