一、ASP.NET (Core)WebApi参数传递实操演练
1、什么是contentType
和dataType
?
$.ajax
contentType
和 dataType
, contentType
主要设置你发送给服务器的格式,dataType
设置你收到服务器数据的格式。
更简单的解释:
contentType
: 告诉服务器,我要发什么类型的数据。
dataType
:告诉服务器,我要想什么类型的数据。
在http
请求中,get
和 post
是最常用的。在 jquery 的 ajax
中, contentType
都是默认的值:application/x-www-form-urlencoded
,这种格式的特点就是,name/value
成为一组,每组之间用 & 联接,而 name
与value
则是使用 = 连接。如:wwwh.baidu.com/q?key=fdsa&lang=zh
这是get
, 而 post
请求则是使用请求体,参数不在 url
中,在请求体中的参数表现形式也是: key=fdsa&lang=zh
的形式。
键值对这样组织在一般的情况下是没有什么问题的,这里说的一般是,不带嵌套类型JSON,也就是 简单的JSON,形如这样:
{a:1,b:2,c:3}
但是在一些复杂的情况下就有问题了。例如在 ajax
中你要传一个复杂的 json
对像,也就说是对象嵌数组,数组中包括对象,如果你这样传:
{data: {a: [{x:2}] }}
这个复杂对象,application/x-www-form-urlencoded
这种形式是没有办法将复杂的 JSON
组织成键值对形式(当然也有方案这点可以参考) ,你传进去可以发送请求,但是服务端收到数据为空, 因为 ajax 没有办法知道怎样处理这个数据。
这怎么可以呢?
聪明的程序员发现 http 还可以自定义数据类型,于是就定义一种叫 application/json
的类型。这种类型是 text
, 我们 ajax
的复杂JSON数据,用 JSON.stringify
序列化后,然后发送,在服务器端接到然后用 JSON.parse
进行还原就行了,这样就能处理复杂的对象了。
$.ajax({
dataType: 'json',
contentType:
'application/json',
data: JSON.stringify({a: [{b:1, a:1}]}
)})
2、什么是参数绑定(Parameter Binding
)?
Asp.NET Web API中Controller
是如何解析从客户端传递过来的数据,然后赋值给Controller
的参数的,也就是参数绑定或者模型绑定。
常见的绑定方式有如下四种。
- 路由值(
Route Values
):通过导航到路由如{controller}/{action}/{id}
此时将绑定到id参数。 - 查询字符串(
QueryStrings
):通过查询字符串中的参数来绑定,如name=Jeffcky&id=1
,此时name
和id
将进行绑定。 - 请求
Body
(Body
):通过在POST
请求中将数据传入到Body
中此时将绑定如上述Person
对象中。 - 请求
Header
(Header
):绑定数据到Http
中的请求头中,这种相对来说比较少见。
所以通过上述讲述我们知道有多种方式将数据从客户端传递到服务端,然后模型绑定会自动为我们创建正确的方法来绑定到后台参数中,简单和复杂的类型参数都会进行绑定。
3、ASP.NET WebAPI中FromUri
和FromBody
两类特性区别
1)、【FromUri
】特性
应用【FromUri
】特性,Web API Action中参数将从URL中解析数据。
查询字符串(QueryStrings
):通过查询字符串中的参数来绑定,如name=Jeffcky&id=1
,此时name
和id
将进行绑定,对应WebAPI中媒体
类型格式化器JsonMediaTypeFormatter
,对应的content-type
是:application/json
!
2)、【FromBody
】特性
应用【Frombody
】特性,Web API Action
中参数将从请求体(Request Body
),并且通过媒体类型格式化器获取和绑定数据。
请求Body
(Body
):通过在POST
请求中将数据传入到Body
中此时将绑定如上述Person
对象中,对应WebAPI中媒体类型格式化器
FormUrlEncodedMediaTypeFormatter
,对应的content-type
是:application/x-www-form-urlencoded
!
注意:对多个参数使用FromBody
不起作用!!!
二、实战运用(PS:一般这几种场景就能够满足我们实际开发工作需要了)
1、ASP.NET WebApi参数传递实操演练
2、ASP.NET Core WebApi参数传递实操演练
三、总结
其实说了这么多,简单类型绑定和复杂类型绑定在本质上没什么太大的区别,真正的区别在于数据绑定是通过GET请求还是POST请求 。
说白了就是【FromUri
】特性和【FromBody
】特性之间的区别。
【FromUri
】和【FromQuery
】 :一般用与单个简单类型的参数。
【FromBody
】 :一般用于将多个简单类型的参数打包成一个复杂对象类型的参数 。
注意:对多个参数使用FromBody
不起作用,即也就是说,[FromBody
] 修饰的参数只能有一个。
.NetCore WebApi传输参变化
.NetCore 的 WebApi,一般以前的mvc5,继承自 ApiController
,则是WebApi
,采用独有的管道处理模型,再Core
中,一般是 继承自 ControllerBase
,控制器类上标注 [ApiController]
1.前端代码
//NetCoreWebApi中,传输 application/json; 格式的,后端无需加[FormBody]也能拿到值
$.ajax({
type: "post",
url: "/api/WebApi/ww",
data: JSON.stringify( { a: 1, b: 2,c: 4,"yy":99,"bb":"匹配"} ), //如果没有序列化,后端获取不到,序列化了,WebApi不需要加 FormBody,能拿到值,contentType: "application/json;charset=utf-8"//不加上 默认不是表单的那种也不是json那种
contentType: "application/x-www-form-urlencoded",//这个类型无法指定
data: { a: 1, b: 2,c: 4,"yy":99,"bb":"匹配"},
})
2.后端代码
[HttpPost]
[Route("ww")]
public string Po(KJ k, int yy, string bb)
{
//k null
//yy 0
//b null
}
3.结论:
因为前端指定了,传输类型为,"application/x-www-form-urlencoded
",就算不写contentType
,它的默认值也是“application/x-www-form-urlencoded
”,但是指定失败
最后的请求格式:application /problem+json; charset=utf-8
报错为:415
解决:指定为 json
传输,序列化后传输,后端就可以拿到值 (可以不用[FormBody]
),核心都在传输的 contentType
[HttpPost]
[Route("E3")]
public string fdasfs([BindAttribute(include: "a,b")] [FromBody] KJ p, int r = 0)
{
//******************.Net Core Mvc WebApi的post的使用**************************/
//1.前端指定的application/json,传输json数据,不管有没有[FromBody]都可以拿到值
/*2.前端指定的application/x-www-form-urlencoded,传输json数据或者json对象,失败,
*明明设置了传输类型,但是却成了 application /problem+json; charset=utf-8,导致请求失败
3.如果传入的除了一个实体,还有其他参数,那就都绑定不上 都没有拿到值
前端是这样的:{user: {a: 1, b: 9}, r: 99} 就是不行的,
{a: 1, b: 9}可行的
必须整成一个实体
/* var json = { user: { a: 1, b: 9, }, r: 99 };
$.ajax({
url: "/api/mm/E3",
type: "post",
//contentType:"application/x-www-form-urlencoded",//写成这种,写了也白写,最终传输类型被覆盖
contentType:"application/json",
data:JSON.stringify(json)
}); */
/* 4.NetCore的 BindAttribute特性 在 contentType:"application/json 不起作用,不能绑定指定的属性,在
contentType:"application/x-www-form-urlencoded 表单中完全可以,过滤掉不需要的属性
FormData
a:1
b:9
*/
return "OK";
}