[英]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);
}
}
}
所有沒有附加 {id} 的 POST 方法都可以工作。 但是由於我們長期擁有大量舊客戶端,因此我必須保持舊版本正常運行,並且無法刪除舊控制器中的 {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 }
);
知道我做錯了什么或如何解決這個問題嗎?
該問題與版本控制無關。
帶有id
參數的方法不起作用的原因是您有沖突路線:
[Route("api/version")]
和
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
對於具有Route("api/version")
屬性的名為Version
控制器,您只能擁有屬性路由或常規路由(MVC / WebAPI 路由),但不能同時擁有兩者。
在您的情況下,屬性路由覆蓋了 MVC 一個,因此api/version/{id}
不再存在。 但是api/version?id
仍然有效,因為它是由屬性路由尋址的。
要解決該問題,您可以將控制器上的屬性路由更改為RoutePrefix
而不是Route
,並在必要時在每個操作上使用帶有相對路徑的Route
。
必要意味着您有無法通過常規路由尋址的路由。
[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);
}
}
問題是您有 2 個 post 方法,而 api 不知道如何識別/生成資源名稱。
您需要做的是添加重復方法名稱的自定義資源名稱。
因此,如果我們以您的示例為例,您可以將資源添加到拋出異常的資源並保留另一個資源,或者為它們提供唯一的資源名稱。
例如像[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)
如果你真的不想使用參數,那么你可以傳遞你自定義的對象類並做一些類似的事情,而不用測試它:
Post([FromBody]MyCustomObjectClass data)
而你MyCustomerObjectClass
:
class MyCustomObjectClass {
public int? Id { get; set; }
public dynamic Value { get; set; }
}
比您不需要 2 個 post 方法,您可以只有一個,並且 Id 可以是可選的。
只是為了不要混淆你。 糟糕的是我在帖子中使用了像[HttpPost("id")]
這樣的[HttpPost("id")]
作為命名約定,它與您的方法 Id 參數無關。 在這種情況下, id
只是資源的名稱,它對操作沒有影響。 所以你可以稱它為適合你的邏輯[HttpPost("post1")]
和[HttpPost("post2")]
。
最后一個建議,使用 dynamic 進行測試並在短時間內啟動 api 很好,但我總是使用靜態類型對象。
我強烈建議看看這個。
嘗試
[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);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.