基於.Net Framework 4.0 Web API開發(2):ASP.NET Web APIs 參數傳遞方式詳解


概述: 

  ASP.NET Web API 的好用使用過的都知道,沒有復雜的配置文件,一個簡單的ApiController加上需要的Action就能工作。調用API過程中參數的傳遞是必須的,本節就來談談API使用過程中參數的傳遞方式。

各種參數傳遞方式的實現:

      ASP.NET Web API參數有兩種傳遞方式,一種是請求時攜帶QueryString,Action中沒有表中標注FromUri和FromBody屬性且沒有默認值的參數,Request請求時必需一QueryString的方式攜帶參數?A=&B=&C=1,及時沒有值,也得傳遞,否則報404錯誤。

  API 開發中的FromUriAttribute屬性,主要是用來在GET請求中傳遞復雜對象,並且每個API可以含有多個此類型的參數,但每個復雜對象中的屬性名不能相同,否則無法正確傳值,除非兩個參數的相同屬性的屬性值相同,不過此種方式傳遞有一定的局限性,就是url長度限制,變相的限定此種方式的參數數據量的大小。

     另外一種傳遞方式就是請求Request的發送內容攜帶數據,對應API開發中的FromBodyAttribute屬性,此種方式主要應對POST請求參數的傳遞,可以傳遞復雜的類型,包括數組,list等,但是每個API有且僅有一個這樣的參數,如果有多個,就會報無法將多個參數綁定到請求的內容

  不多上,下面上代碼,一種一種講解:

 1. 簡單類型傳遞

  簡單類型包括 int(decimal,long,float)、string(char)、bool、datetime、guid,主要就這幾種

     模板: public  TResult nameOfFunction([FromUrl]int i, [FromUrl]string s, ……)

         => public  TResult nameOfFunction(int i, string s, ……)

   但模板: public  TResult nameOfFunction([FromUrl]ClassA a, [FromUrl]Class b, ……)

         ≠> public  TResult nameOfFunction(ClassA a, ClassB b, ……)

 1         [HttpGet]
 2         public ResultData TestParameter(int i, string s, bool b, DateTime t, Guid g)
 3         {
 4             try
 5             {
 6                 var data = new { i = i, s = s, b = b, t = t, g = g};
 7                 return new ResultData(data);
 8             }
 9             catch (Exception ex)
10             {
11                 throw ex;
12                 //return new ResultData(ResultType.SystemException, ex.Message);
13             }
14         }
15 
16         //TestParameter
17 function TestParameter() {
18     var v = { i: 1, b: false, t: "2016-07-06", g: "E816F0B7-2FB7-47D9-84ED-119F58C9BEC5", s: "test"};
19     $.ajax({
20         type: "get",
21         url: host + "/mobileapi/test/TestParameter",
22         dataType: "text",
23         data: v,
24         success: function (data) {
25             alert(data);
26         },
27         error: function (x, y, z) {
28             alert("報錯無語");
29         }
30     });
31 }

結果如下:

注意:

 1. GET 類型請求的API不能含有[FromBody]屬性的參數,雖然不會報錯,但永遠沒為null,如果GET請求需要傳遞復雜參數,可以用FromUri屬性修飾參數

 2. API參數沒有默認值的情況下,請求的參數名稱必需與API參數名稱保持一致,但不區分大小寫,且能對應上的參數個數一定相等,否則會報404錯誤。

詳細列舉如下:

     a. 參數個數相等,但對應的參數少個 g,所有找不到對應API,報404錯誤

 1 function TestParameter() {
 2     var v = { i: 1, b: false, t: "2016-07-06", s: "test", a: "會報404錯誤" };
 3     $.ajax({
 4         type: "get",
 5         url: host + "/mobileapi/test/TestParameter",
 6         dataType: "text",
 7         data: v,
 8         success: function (data) {
 9             alert(data);
10         },
11         error: function (x, y, z) {
12             alert("報錯無語");
13         }
14     });
15 }

     b. 參數個數不相等,但是能對應上的參數個數相等,不會報404錯誤

 1 //TestParameter
 2 function TestParameter() {
 3     var v = { i: 1, b: false, t: "2016-07-06", s: "test", g: "E816F0B7-2FB7-47D9-84ED-119F58C9BEC5", a: "不會報404錯誤" };
 4     $.ajax({
 5         type: "get",
 6         url: host + "/mobileapi/test/TestParameter",
 7         dataType: "text",
 8         data: v,
 9         success: function (data) {
10             alert(data);
11         },
12         error: function (x, y, z) {
13             alert("報錯無語");
14         }
15     });
16 }

  如何調整使上述幾種方式也能找到正確的API的呢?這就需要.NET Framework的默認參數功能,API的調整如下:

 1  [HttpGet]
 2         public ResultData TestParameter(int i, string s, bool b, DateTime t, Guid? g = null)
 3         {
 4             try
 5             {
 6                 var data = new { i = i, s = s, b = b, t = t, g = g };
 7                 return new ResultData(data);
 8             }
 9             catch (Exception ex)
10             {
11                 throw ex;
12                 //return new ResultData(ResultType.SystemException, ex.Message);
13             }
14         }

 以上代碼最后一個參數g有個默認值null,這樣get請求的時候可以沒有g參數也能請求通過,不會報404錯誤。另外,值類型的參數最好定義為nullable形式(簡寫可以?標注),這樣的參數賦值不正確的時候也不會報異常錯誤,只是參數值為null。特別是日期類,如果不是nullable類型,不傳值和傳錯值都會報異常

     上面例子中的t參數如果為   TestParameter?i=1&b=false&t=2016-37-06&s=test&g=E816F0B7-2FB7-47D9-84ED-119F58C9BEC5或者

 http://192.168.1.135:1507/mobileapi/test/TestParameter?i=1&b=false&t=&s=test&g=E816F0B7-2FB7-47D9-84ED-119F58C9BEC5,都會報錯,如果定義為nullable類型就一切正常:   public ResultData TestParameter(int i, string s, bool b, DateTime? t, Guid? g = null)。

2. 復雜類型傳遞

 GET請求中復雜類型的傳遞需要FormUriAttribute屬性配合,並且每個API可以有多個FromUri標示的參數,也可以在post請求中使用此屬性標注的參數。

 1  [HttpGet]
 2         public ResultData TestParameter2([FromUri]List<int> ids, [FromUri]User a) 3  { 4 try 5  { 6 var data = new { ids=ids, name=a.name }; 7 return new ResultData(data); 8  } 9 catch (Exception ex) 10  { 11 throw ex; 12 //return new ResultData(ResultType.SystemException, ex.Message); 13  } 14 }

   測試代碼:

 1 function TestParameter2() {
 2     var v = { ids: [1, 2, 3], name='test', age=4, weight=100 }; 3  $.ajax({ 4 type: "get", 5 url: host + "/mobileapi/test/TestParameter2", 6 dataType: "text", 7 data: { "": v }, 8  beforeSend: function (request) { 9 request.setRequestHeader("token", $("#token").val()); 10  }, 11  success: function (data) { 12  alert(data); 13  }, 14  error: function (x, y, z) { 15 alert("報錯無語"); 16  } 17  }); 18 }

   測試結果:GET請求中可以利用FromUri屬性傳遞復雜類型

 

    POST請求中復雜類型的傳遞需要FormBodyAttribute屬性配合,並且每個API有且僅有一個FromBody標示的參數,並且只能在post請求中使用。

 1  [HttpPost]
 2         public ResultData TestParameter2([FromBody]List<int> ids, [FromBody]List<int> ids2)
 3         {
 4             try
 5             {
 6                 var data = new { ids=ids, ids2=ids2 };
 7                 return new ResultData(data);
 8             }
 9             catch (Exception ex)
10             {
11                 throw ex;
12                 //return new ResultData(ResultType.SystemException, ex.Message);
13             }
14         }

 

 1         [HttpPost]
 2         public ResultData TestParameter2([FromBody]List<int> ids, [FromBody]ProductData pd)
 3         {
 4             try
 5             {
 6                 var data = new { ids = ids, pd = pd };
 7                 return new ResultData(data);
 8             }
 9             catch (Exception ex)
10             {
11                 throw ex;
12                 //return new ResultData(ResultType.SystemException, ex.Message);
13             }
14         }

以上兩個示例中代碼編譯不報錯,可以正常編譯,但是請求會報錯,報錯信息如下:

   測試代碼:

 1 function TestParameter2() {
 2     var v = { ids: [1, 2, 3], ids2: [4, 5, 6] };
 3     $.ajax({
 4         type: "post",
 5         url: host + "/mobileapi/test/TestParameter2",
 6         dataType: "text",
 7         data: { "": v },
 8         beforeSend: function (request) {
 9             request.setRequestHeader("token", $("#token").val());
10         },
11         success: function (data) {
12             alert(data);
13         },
14         error: function (x, y, z) {
15             alert("報錯無語");
16         }
17     });
18 }

   

 1 function TestParameter2() {
 2     var v = { "ids": [1, 2, 3], pd: { barcode: "ddddd" } };
 3     $.ajax({
 4         type: "post",
 5         url: host + "/mobileapi/test/TestParameter2",
 6         dataType: "text",
 7         data: { "": v },
 8         beforeSend: function (request) {
 9             request.setRequestHeader("token", $("#token").val());
10         },
11         success: function (data) {
12             alert(data);
13         },
14         error: function (x, y, z) {
15             alert("報錯無語");
16         }
17     });
18 }

測試結果:

 以上兩組測試都會報無法將多個參數綁定到請求的內容異常

3. 數組參數的正確傳遞

   調整一下API,只接收一個FromBody參數,並為List<int>

 1         [HttpPost]
 2         public ResultData TestParameter2([FromBody]List<int> ids)
 3         {
 4             try
 5             {
 6                 var data = new { ids = ids, pd = pd };
 7                 return new ResultData(data);
 8             }
 9             catch (Exception ex)
10             {
11                 throw ex;
12                 //return new ResultData(ResultType.SystemException, ex.Message);
13             }
14         }

測試一:

 1 //TestParameter
 2 function TestParameter2() {
 3     var v = { "ids": [1, 2, 3] };
 4     $.ajax({
 5         type: "post",
 6         url: host + "/mobileapi/test/TestParameter2",
 7         dataType: "text",
 8         data: { "": v },
 9         beforeSend: function (request) {
10             request.setRequestHeader("token", $("#token").val());
11         },
12         success: function (data) {
13             alert(data);
14         },
15         error: function (x, y, z) {
16             alert("報錯無語");
17         }
18     });
19 }

測試一的結果:

測試二:

 1 //TestParameter
 2 function TestParameter2() {
 3     var v = { "": [1, 2, 3] };
 4     $.ajax({
 5         type: "post",
 6         url: host + "/mobileapi/test/TestParameter2",
 7         dataType: "text",
 8         data: { "": v },
 9         beforeSend: function (request) {
10             request.setRequestHeader("token", $("#token").val());
11         },
12         success: function (data) {
13             alert(data);
14         },
15         error: function (x, y, z) {
16             alert("報錯無語");
17         }
18     });
19 }

測試二結果:

分析: 經過測試一和測試二結果觀察,數據傳遞格式不能數組名,其實這個不是數組傳遞的問題,而是WEB API frombody參數的一種約定,所以每個API只能有一個frombody格式的參數,因為這樣的參數不會依據屬性名對應解析,而是把body中發送的所有數據解析成一個對象,所以無法定義多個 frombody 格式參數。

結論: 經過frombody修飾的參數只能有一個,並且經過frombody修飾的參數無論是簡單類型,還是復雜類型(包括數組,list,系統class和自定義class等),傳參都不需要屬性名,屬性名必需為空字符串(“”),否則無法解析,參數永遠為null

參數格式的列舉:

簡單類型json參數格式: {"":1} 、{"":1.0} 、{"":"test"} 、{"":"C"} 、{"":"2016-03-10"} 、{"":"BC069BF1-1382-4C5D-B3B1-9643F3F94A9D"} 

類定義如下:

1     public class User
2     {
3         public string Name { get; set; }
4         public int Age { get; set; }
5         public DateTime? Birthday { get; set; }
6     }

類類型json參數格式:{name:"Tom", age:18, birthday:"2016-03-10"}

4. FromUrl參數和FromBody參數混合使用,這種混合使用規則參照以上使用方法,沒難度。

 1         [HttpPost]
 2         public ResultData TestParameter2(int i, string s, [FromUri]bool b, DateTime? t, Guid? g = null, [FromBody]List<int> ids = null)
 3         {
 4             try
 5             {
 6                 var data = new { ids = ids };
 7                 return new ResultData(data);
 8             }
 9             catch (Exception ex)
10             {
11                 throw ex;
12                 //return new ResultData(ResultType.SystemException, ex.Message);
13             }
14         }

 

此篇到此結束,歡迎大家討論!

 補充:API中Action參數傳遞方式總結說明

    1. 參數不帶任何屬性標簽   Action F1(string a, string b)

         querystring中必需含有 a和b查詢字符串   url?a=1&b=, 即使b沒有值,也必需攜帶,否則報404錯誤,找不到符合請求的Action

    2. 參數帶有fromuri屬性  Action F2(string a, [FromUri]stirng b)

   querystring中必需含有 a查詢字符串,b可以不帶,因為被屬性[FromUri]修飾,例: url?a=1&b=或url?a=1都能匹配到F2 action, b沒有值可以不攜帶,但參數a必需攜帶

    3. 帶有fromuri屬性的參數可以有多個  Action F3(string a, [FromUri]stirng b,[FromUri]stirng c,[FromUri]stirng d) ,

   請求方法同2, 例如: url?a=1&b=2&d=3

    4. 帶有frombody屬性的參數只適應post請求,否則永遠為null ,並且可以與fromuri混合使用,但每個action,frombody屬性參數有且僅有一個,多個會報錯

           Action F4(string a, [FromUri]stirng b,[FromUri]stirng c,[FromBody]stirng d)

    使用方法同 2, 3

      這樣混合使用不報錯,也能正常運行,但需要混合使用的環境比較少,基本上95% Action只用fromuri或frombody就能完成,沒必要混合使用

      

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM