概述:
ASP.NET Web API 的好用使用过的都知道,没有复杂的配置文件,一个简单的ApiController加上需要的Action就能工作。调用API过程中参数的传递是必须的,本节就来谈谈API使用过程中参数的传递方式。
各种参数传递方式的实现:
ASP.NET Web API参数有两种传递方式,一种是请求时携带QueryString,对应API 开发中的FromUrlAttribute属性,也是参数传递默认属性,并且每个API可以含有多个此类型的参数,主要应对GET请求,但此种方式传递有一定的局限性,比如复杂类型的参数,此种传递方式就不能胜任,就像常用的数组参数也不能用此种方式传递,还有就是url长度限制,变相的限定此种方式的参数数据量的大小。
另外一种传递方式就是请求Request的发送内容携带数据,对应API开发中的FromBodyAttribute属性,此种方式可以传递复杂的类型,包括数组,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, ……)
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
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. 复杂类型传递
复杂类型的传递需要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, 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 }
此篇到此结束,欢迎大家讨论!