在这篇文章中,我们将学习Web API如何将HTTP请求数据绑定到一个操作方法的参数中。
操作方法在Web API控制器中可以有一个或多个不同类型的参数。它可以是基本数据类型或复杂类型。Web API根据URL的查询字符串或请求主体中参数类型来绑定操作方法的参数。
如果参数类型是基本数据类型(int,double,string,DateTime,bool等),Web API默认将会从URL中获取参数值(即通过query string)获取。
如果参数类型的复杂类型,Web API默认从请求主体中获取参数值。
下表列出了Web API参数绑定的默认规则。
HTTP方法 | Query String | Request Body |
GET | 简单类型 | 不能从请求主体中获取参数值 |
POST | 简单类型 | 复杂类型 |
PUT | 简单类型 | 复杂类型 |
PATCH | 简单类型 | 复杂类型 |
DELETE | 简单类型 | 不能从请求主体中获取参数值 |
我们先来看看创建带MVC的Web API项目时自动生成的Values控制器是如何定义的。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Net; 5 using System.Net.Http; 6 using System.Web.Http; 7 8 namespace WebAPIContainMVC.Controllers 9 { 10 public class ValuesController : ApiController 11 { 12 // GET api/values 13 public IEnumerable<string> Get() 14 { 15 return new string[] { "value1", "value2" }; 16 } 17 18 // GET api/values/5 19 public string Get(int id) 20 { 21 return "value"; 22 } 23 24 // POST api/values 25 public void Post([FromBody]string value) 26 { 27 } 28 29 // PUT api/values/5 30 public void Put(int id, [FromBody]string value) 31 { 32 } 33 34 // DELETE api/values/5 35 public void Delete(int id) 36 { 37 } 38 } 39 }
从Values控制器的定义中,我们可以得出如下几个结论:
(1)Web API常规的方法有四个:Get(),Post(),Put()和Delete()。
(2)四种方法的参数可以归纳为两大类:URL传递(Request-url)和Body(Request-body)传递。
(3)可以将四种方法的参数传递归为两大类,而这两大类又集中在Get和Post中体现(Put是Get和Post的组合,Delete和Get类型),所以说研究Web API的参数绑定,只需要研究Get和Post方法的参数传递即可,Get对应Request-url,Post对应Request-Body。
在本篇文章中,客户端调用使用Fiddler工具进行测试。
一、Get
1、基本数据类型作为方法参数
1.1 方法只含有一个参数(形参可以传递进来)
方法定义如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Net; 5 using System.Net.Http; 6 using System.Web.Http; 7 using WebAPIContainMVC.Entity; 8 9 namespace WebAPIContainMVC.Controllers 10 { 11 public class StudentController : ApiController 12 { 13 [HttpGet] 14 public string GetStudentById(int id) 15 { 16 string strResult=string.Empty; 17 List<Student> list = new List<Student>(); 18 Student stu = new Student() 19 { 20 StudentId=1, 21 Name="Tom", 22 Age=20, 23 Sex="男" 24 }; 25 list.Add(stu); 26 list.ForEach(p => 27 { 28 if (p.StudentId.Equals(id)) 29 { 30 strResult = "存在该学生信息"; 31 } 32 else 33 { 34 strResult = "对不起,找不到该学生信息"; 35 } 36 }); 37 38 return strResult; 39 } 40 } 41 }
客户端调用
结果:
双击左侧的进程,得到如下的结果
1.2、方法含有多个参数(形参可以传递进来)
方法定义如下:
public string GetStudentByIdAndName(int id,string name) { string strResult = string.Empty; List<Student> list = new List<Student>(); Student stu = new Student() { StudentId = 1, Name = "Tom", Age = 20, Sex = "男" }; list.Add(stu); list.ForEach(p => { if (p.StudentId.Equals(id)&&p.Name.Equals(name)) { strResult = "存在该学生信息"; } else { strResult = "对不起,找不到该学生信息"; } }); return strResult; }
URL地址:http://localhost:63512/api/student?id=1&&name=Tom
结果如下:
2、实体对象类型作为方法参数(形参不能传递进来)
方法定义如下:
[HttpGet] public string GetStudent(Student student) { string strResult = string.Empty; List<Student> list = new List<Student>(); Student stu = new Student() { StudentId = 1, Name = "Tom", Age = 20, Sex = "男" }; list.Add(stu); if (student != null) { list.ForEach(p => { if (p.StudentId.Equals(student.StudentId)) { strResult = "存在该学生信息"; } else { strResult = "对不起,找不到该学生信息"; } }); } else { strResult = "参数值为Null"; } return strResult; }
客户端调用结果如下:
3、基本数据类型和实体对象混合作为方法参数(基本数据类型可以传递进来,实体对象不能传递进来)
4、总结
(1)查询字符串参数名称和操作方法参数名称必须相同(不区分大小写)。参数的先后顺序可以不一致。
(2)Get()参数传递的本质是URL字符串拼接,但是URL字符串的长度受限制。
(3)Get()的参数支持基本数据类型,不支持实体数据类型。
(4)Get()参数的传递是在Http请求的头部传递,而不支持Request-Body传递。
(5)Get类型的方法命名,尽量采用“Get+方法名”的命名方式,在方法前面加上特性:[HttpGet]。
二、Post
1、Post参数传递是在Request-Body内传递。
2、Post参数可以传递基本数据类型,也可以传递实体数据类型。
3、Post操作方法只能包含一个实体数据类型,因为只能允许一个参数读取Request-Body中的数据。
4、Post传递参数时,无论是基本类型参数还是实体类型,均需要借助[FromBody]特性。(有些情况下不写[FromBody]特性也可以把参数传递进来,但为了规范化,最好是加上该特性)。
5、Post类型的方法命名,尽量采用“Post+方法名”的命名方式,在方法前面加上特性:[HttpPost]。
三、FromURI与FromBody
在默认情况下,Web API是从查询字符串中得到基本数据类型参数的值,从请求主体中得到复杂类型参数的值,如果想改变这种默认情况怎么办?
可以使用[FromURI]属性,是Web API从查询字符串中获取复杂类型参数的值,使用[FromBody]属性可以使Web API从请求主体中获取基本数据类型参数的值。
例如下面的Get方法
[HttpGet] public string GetStudentById([FromUri]Student stu) { }
Get方法中包括复杂的类型参数,参数添加了[FromUri]属性,Web API将试图从查询字符串中得到Student类型参数的值。
同样,参考下面的Post方法:
[HttpPost] public string Post([FromBody]string name) { }
Web API将从请求主体中获取基本类型参数的值,而不是从请求字符串中获取。