1. 程式人生 > >ASP.NET MVC Web API Post FromBody(Web API 如何正確 Post)

ASP.NET MVC Web API Post FromBody(Web API 如何正確 Post)

原文:ASP.NET MVC Web API Post FromBody(Web API 如何正確 Post)

問題場景:

ASP.NET MVC Web API 定義 Post 方法,HttpClient 使用 JsonConvert.SerializeObject 傳參進行呼叫,比如 Web Api 中定義 AddProduct 方法,引數為 Product 的各類資訊(id、name等),然後操作完之後返回處理資訊。
問題分析:

曾經在之前寫過一篇 Web API 的博文《初試ASP.NET Web API/MVC API(附Demo)》,但只是講解了 Get 的用法,因為比較簡單,通過 URL 就可以進行傳參,比如 URL:

http://localhost:9283/api/product/get/1 ,這個就表示在控制器 Product 中獲取 ID 為 1 的 Product,客戶端不需要配置什麼,直接在 HttpClient 中傳入這個 URL 就可以了。

Web API 中使用 Post 的方式可以參考《HttpClient + ASP.NET Web API, WCF之外的另一個選擇》,我按照文中的方式試了下,程式碼如下:

ProductController 程式碼:

 public class ProductController : ApiController
{
        [HttpPost]
        public int AddProduct(string id, string name)
        {
             return 1;
        }
}

HttpClient 測試呼叫程式碼:

[Fact]
public void WebApiTest_AddProduct()
{
      using (var client = new HttpClient())
      {
          client.BaseAddress = new Uri("http://localhost:1661/");
          var requestJson = JsonConvert.SerializeObject(
          new
          {
              id = "1",
              name = "2"
          });
         HttpContent httpContent = new StringContent(requestJson);
         httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
         var result = client.PostAsync("api/Product/AddProduct",     
         httpContent).Result.Content.ReadAsStringAsync().Result;
      }
}

MapHttpRoute 路由配置:

public static void Register(HttpConfiguration config)
{
      config.Routes.MapHttpRoute(
      name: "DefaultApi",
      routeTemplate: "api/{controller}/{action}/{id}",
      defaults: new { id = RouteParameter.Optional }
      );
}

看起來似乎沒什麼問題,但為什麼會報“在控制器“Product”上找不到與該請求匹配的操作。”錯誤呢?從異常資訊可以看出,應該是路由問題,也就是說找不到 Action-AddProduct,但是寫的路由配置沒什麼問題啊(我自己認為),然後網上各種關鍵字搜尋,找了很多資料,我也試了很多方式,因為對 WEB API 的路由配置不是很熟悉,然後新建 Demo,一點一點的進行測試,發現幾個點,比如路由預設配置是沒有 {action} 的,還有就是上面測試程式碼中 PostAsync,預設不知道為什麼會當作 Get 使用,比如我們在 AddProduct 方法中去掉一個 name 引數,這時候我們測試會發現是執行 AddProduct,但是引數 id 變成了“AddProduct”,顯然 action 的名字當作了 id 的值,這個我覺得有兩個原因,一個是我路由配置沒有配置好,還有就是測試客戶端的程式碼寫的有問題,因為急著解決這個問題,所以也沒有研究這其中的原因,最後發現了 FromBody(只能標識一個),我之前在找問題的過程中,也是使用過它,但是當時並沒有成功,現在也忘了當時的程式碼是怎麼寫的了。

記錄一下 Post 可以執行的方式。

ProductController 程式碼:

public class ProductController : ApiController
{
      [HttpPost]
      public int AddProduct([FromBody] Product product)
      {
          return 1;
      }
      public class Product
      {
          public string id { get; set; }
          public string name { get; set; }
      }
}

測試程式碼和路由配置沒有變化,測試結果: