1. 程式人生 > 其它 >【WebApi系列】詳解WebApi如何傳遞引數

【WebApi系列】詳解WebApi如何傳遞引數

原文地址:https://www.cnblogs.com/wangjiming/p/8378108.html

一 概述

一般地,我們在研究一個問題時,常規的思路是為該問題建模;我們在研究相似問題時,常規思路是找出這些問題的共性和異性。基於該思路,我們如何研究WebApi引數傳遞問題呢?

首先,從引數本身來說,種類較為多(如int,double,float,string,array,Object等),且有些型別較為複雜(如值型別和引用型別的機制等);

其次,從基於WebApi的Http請求方法來說,種類多且不盡相同(如Get,post,Delete,put,head等),在上一篇文章 :【WebApi系列】淺談HTTP在WebApi開發中的運用

中,我們簡要描述了Http請求的20個方法;

..........

如此複雜且不盡相同,關於WebApi引數傳遞,我們該選擇什麼作為切入點來研究呢?基於我們上面提到的研究思路,我們想到了.NET Framework框架,那麼,我們來看看基於.NET Framework框架的的WebApi

模板是怎樣的呢?

請按圖中步驟操作

我們來看看Values控制器是怎樣的

 1  public class ValuesController : ApiController
 2     {
 3         // GET api/values
 4         public IEnumerable<string> Get()
 5         {
 6             return new string[] { "value1", "value2" };
 7         }
 8 
 9         // GET api/values/5
10         public string Get(int id)
11         {
12             return "value";
13         }
14 
15         // POST api/values
16         public void Post([FromBody]string value)
17         {
18         }
19 
20         // PUT api/values/5
21         public void Put(int id, [FromBody]string value)
22         {
23         }
24 
25         // DELETE api/values/5
26         public void Delete(int id)
27         {
28         }
29     }

從Values控制器,我們不難得出如下幾個結論:

(1)WebApi常規方法為四個:Get,Post,Put和Delete;

(2)四種方法的引數可歸結為兩大類:url傳遞(Request-url)和Body(Request-body)傳遞;

(3)基於(2),我們將四種方法的引數傳遞迴為兩大類,而這兩大類又集中在Get和Post中體現了(Put是Get和Post的組合,Delete與Get類似);

其實,分析到現在,我們很容易找得到了研究WebApi引數傳遞的切入點?研究Get和Post方法引數傳遞即可。是的,沒錯,我們本篇文章就是基於Get和Post方法的引數傳遞,前者對應Request-url,後者對應Reqeust-Body。

二 Get

1 基礎資料型別


1.1 方法只含一個形參(引數傳得進去)

ajax

$(document).ready(function () {
   $("#FindProdcutDetail").click(function () {
       $.ajax({
               type: "Get",
               //url: "/api/Default/GetProductDetails?ProductCode=JX80869"
               url: "/api/Default/GetProductDetails",
               data: { "ProductCode":"JX80869"}
            })
        })           
   })

Result

總結

(1)當Get方法形參為一個且為基本資料型別時,Get方法能接受外部傳遞的值

(2)Get傳值的本質是通過url字串拼接,如上兩兩種url形式的傳遞的結果都是一樣

url形式1

url: "/api/Default/GetProductDetails?ProductCode=JX80869"

url形式2

url: "/api/Default/GetProductDetails",
data: { "ProductCode":"JX80869"}

我們用Goole Chrome來看看結果,發現url形式1和url形式2均一致

(3)Get傳遞引數本質是url字串拼接,Request-Head頭部傳遞,Request-Body中不能傳遞(這是與Post方法的本質區別),我們舉兩個例子

例子1:我們將形參新增[FromBody]屬性後,值傳遞不進去

例子2:我們用PostMan來測試,發現PostMan中,Get方法引數Body為灰色,是不能選中的

1.2 方法含有多個形參(引數傳得進去)

$(document).ready(function () {
   $("#FindProdcutDetail").click(function () {
      $.ajax({
               type: "Get",
               url: "/api/Default/GetProductDetails",
               data: { "ProductCode": "JX80869","ProductName":"YaGao"}
            })
        })
  })

result

2 實體物件型別(引數傳不進去)


model

 1  public class ProductDetail
 2     {
 3         //產品編碼
 4         [Required]
 5         public string ProductCode { get; set; }
 6         //產品名稱
 7         [Required]
 8         public string ProductName { get; set; }
 9         //產品價格
10         [Required]
11         public double  ProductPrice{ get; set; }
12     }

ajax

$(document).ready(function () {
    var productDetail = { "ProductName": "YaGao", "ProductCode": "JX80869", "ProductPrice": 40.5};
        $("#FindProdcutDetail").click(function () {
            $.ajax({
                    type: "Get",
                    url: "/api/Default/ProductDetails",
                    data: productDetail
                })
            })
        })

result:

分析

3 實體物件和基礎資料型別混合(實體傳不進去,基礎資料能傳遞進去)


ajax

1 $(document).ready(function () {
2    $("#FindProdcutDetail").click(function () {
3        $.ajax({
4                 type: "Get",
5                 url: "/api/Default/GetProductDetails",
6                 data: { "_productDetail": "ObjectEntity","ProductName":"YaGao"}
7              })
8         })
9     })

result

4 最小滿足原則(引數傳得進去)


所謂“最小滿足原則”,指外部引數必須至少滿足被呼叫方法的形參(形參個數,形參型別和形參名字),換句話說,被呼叫方法具有的形參,外部引數必須傳遞進來,被呼叫方法沒有

的形參,外部引數傳遞與否都可以,否則將會產生狀態碼404錯誤,用數學集合的思路來理解的話,被呼叫方法的形參相當於外部引數的子集。如下例子,我們舉一個真子集的例子,

即外部傳遞引數的個數大於被調方法的的形參個數。

Ajax

 $(document).ready(function () {
    $("#FindProdcutDetail").click(function () {
       $.ajax({
                type: "Get",
                url: "/api/Default/GetProductDetails",
                data: {"ProductCode": "JX00034", "ProductName": "YaGao", "ProductPrice": 20.5, "PrudcutType": "Daily Necessities"}
                })
            })
        })

result

分析:主要原因是路由規則,路由從url裡面取引數與aciton引數匹配,直到匹配滿足為止,具體詳細深入內容,在【WebApi系列】路由章節分析。

5 url長度限制


url引數長度是有一定限制的,當超過一定長度,會報404錯誤

ajax

 $(document).ready(function () {
            $("#FindProdcutDetail").click(function () {
                $.ajax({
                    type: "Get",
                    url: "/api/Default/GetProductDetails",
                    data: {
                        "ProductCode":
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
                        "JX00034xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 
                    }
                })
            })
        })

result

6 Get規範化


關於Get型別規範化,應注意兩點,避免不必要的錯誤或異常:(1)方法的命名儘量採用:“Get+方法名”的形式 (2)在每個方法上加上特性[HttpGet]。

例子:我們去掉[HttpGet]特性和方法前的Get,看看情況什麼怎樣的

ajax

$(document).ready(function () {
    $("#FindProdcutDetail").click(function () {
        $.ajax({
                 type: "Get",
                 url: "/api/Default/ProductDetails",
                 data: {"ProductCode": "JX00034 "}
             })
         })
    })

Controller

1 public class DefaultController : ApiController
2     {
3         4         //[HttpGet]
5         public string ProductDetails(string ProductCode)
6         {
7             return "values";
8         }
9     }

Result

7 關於實體作為引數傳遞的拓展


7.1 藉助[FromUri]特性傳遞實體

ajax

$(document).ready(function () {
   var GetEntityParam = { "ProductName": "YaGao", "ProductCode": "JX80869", "ProductPrice": 40.5};
      $("#FindProdcutDetail").click(function () {
        $.ajax({
                 type: "Get",
                 url: "/api/Default/ProductDetails",
                 data: GetEntityParam
               })
           })
      })

result

7.2 系列化與反系列化傳遞實體

ajax

$(document).ready(function () {
   $("#FindProdcutDetail").click(function () {
       $.ajax({
                type: "Get",
                url: "/api/Default/ProductDetails",
                data: { "productDetail": JSON.stringify({ "ProductName": "YaGao", "ProductCode": "JX80869", "ProductPrice": 40.5 }) }
             })
         })
     })

result

8 小結


(1)Get引數傳遞的本質是url字串拼接;

(2)url字串長度受限制;

(3)Get引數傳遞在Http請求頭部傳遞,而不支援Request-Body傳遞;

(4)Get型別的方法支援引數為基本型別,不支援實體型別;

(5)Get型別的方法命名,應儘量採用“Get+方法名”的命名方式,且習慣性地在方法前加上[HttpGet特性];

(6)實參與形參的匹配,遵循路由規則;

(7)Get對應DB的Select操作,從這一點來理解,就知道為什麼Http不支援實體物件傳遞的合理性了,因為一般情況,我們都是通過簡單的欄位查詢資訊(對應基本型別),

如ID號,使用者名稱等,而不會通過一個實體查詢資料;

三 Post

1 基本資料型別傳遞


1.1 [FromBody]單個引數傳遞

ajax

result

1.2 dynamic單個引數傳遞

ajax

$(document).ready(function () {
   $("#FindProdcutDetail").click(function () {
      $.ajax({
               type: "Post",
               contentType: 'application/json',
               url: "/api/Default/PostParamToProducts",
               data: JSON.stringify({"ProductCode":"JX00039"})
           })
       })
   })

result

Googel Chrome檢視

2 實體作為引數傳遞


ajax

$(document).ready(function () {
   $("#FindProdcutDetail").click(function () {
      $.ajax({
               type: "Post",
               url: "/api/Default/PostParamToProducts",
               data: { "ProductCode": "JX00036","ProductName":"YaGao","ProductPrice":20.5}
            })
        })
    })

result

我們用Googel Chrome看看

3 實體集合作為引數傳遞


ajax

$(document).ready(function () {
   var list_ProductDetail = [
       { "ProductCode": "JX00031", "ProductName": "ToothPaste", "ProductPrice": "20.5" },
       { "ProductCode": "JX00032", "ProductName": "ToothBrush ", "ProductPrice": "18.9" },
       { "ProductCode": "JX00033", "ProductName": "Pen", "ProductPrice": "199.9" },
       { "ProductCode": "JX00034", "ProductName": "computer", "ProductPrice": "15000.5" }
       ]
   $("#FindProdcutDetail").click(function () {
   $.ajax({
             type: "Post",
             contentType: 'application/json',
             url: "/api/Default/PostParamToProducts",
              data: JSON.stringify(list_ProductDetail)
          })
      })
  })

result

Google Chrome 檢視

4 陣列作為引數傳遞


ajax

$(document).ready(function () {
   var arr = ["a", "b", "c", "d"];
   $("#FindProdcutDetail").click(function () {
      $.ajax({
               type: "Post",
               contentType: 'application/json',
               url: "/api/Default/PostParamToProducts",
               data: JSON.stringify(arr)
            })
       })
  })

Result

我們用Google Chrome看看

5 小結


(1)Post引數傳遞本事是在Request-Body內傳遞,而Get引數傳遞本質是url拼接;

(2)Post引數傳遞不是key/value形式,而Get引數是key/value形式;

(3)Post傳遞引數時,無論是單個引數還是物件,均藉助[FromBody]特性(當然,某些情況去掉[FromBody]特性也可把值傳遞進去,但未了規範化,儘量加上該特性);

(4)Post沒長度限制,而Get有長度限制(一般為1024b);

(5)Post相對Get,較安全;

(6)Post操作相當於DB的Insert操作;

四 總結

1.雖然HTTP請求方法有20多種,常用的大致為4種,即Get,Post,Put,Delete(當然,像Trace,Head等也常用);

2.Get,Post,Put,Delete分別對應DB的Select,Insert,Update和Delete操作;

3.WebApi引數型別,大致分為基本資料類型別和物件資料型別(當然你也可以理解為抽象資料型別);

4.研究WebApi引數傳遞,只需研究Get和Post即可,因為其他http方法引數傳遞基本都是有這兩種組合而成(如Put有Get和Post組合而成),或者相似(如Delete與Get相似);

5.對於控制器方法,儘量參照規範格式寫,如在相應控制器方法上加上對應的htt請求(Get對應[HttpGet],Post對應[HttpPost]),方法名儘量採用“Http請型別+方法名”格式(如Get請求,建議採用Get+MethodName;Post請求對應Post+MethodName);

6.WebApi引數請求,大致分為兩大型別,即Request-url和Request-body;

7.文中我們還簡要分析了Get和Post區別;

8.關於如何設計一個良好的介面,在文章中,我們觸及了一下,但未研究,會在後續的文章中單獨分析;