簡體   English   中英

帶有 id 的 ASP.NET WebAPI 2 版本控制 POST

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM