概述:
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就能完成,沒必要混合使用