序列化和模型绑定

两种内置的序列化器

Web API为我们内置了两种序列化器,即JSON和XML,具体使用哪一个依请求头中Accept值来决定。Accept用来指定响应内容的格式(也称媒体类型),常见的媒体类型有以下几个,如图。

image

1.为什么请求同一个资源,IE和Chrome得到的结果不一样呢?

默认情况下,请求同一个资源,比如:GET api/contact/searchcontactbyid/001,IE拿到的是JSON,而Chrome 拿到的即是XML,这是为什么呢?

仔细分析就会发现,是它们的请求头的Accept不一样导致的, Chrome显式指定了application/xml,而IE没有显示指定。

2.自定义序列化器

我们也可以自定义一个序列化器加到Web API中,步骤如下。

①定义一个序列化器继承MediaTypeFormatter或BufferedMediaTypeFormatter。

②将序列化器加入到Web API处理管道中,方法如下图。

image

定制序列化

对于默认的JSON和XML序列化器,我们可以对其行为定制,比如控制哪些字段可以被序列化,日期格式,缩进等等。下面就以JSON序列化器为例来介绍。

1.忽略字段

默认情况下,所有的共有字段和属性都会被序列化。如果想忽略其中某个字段,有两种方法可以实现。

①方法1,使用JsonIgnore特性,下面代码中字段ProductCode就不会被序列化,如下图。

image

②方法2,除了使用json.net自带的特性外,我们还可以使用内置的方法,命名空间System.Runtime.Serialization下的DataContract和DataMember,如果想忽略某个字段,不给它加DataMember特性就可以。当然,内置方法与JsonIgnore不同的地方在于,DataMember还可以序列化私有成员。

image

2.是否缩进

可以通过指定json.net的formatting选项来决定是否缩进,默认值是None即不缩进,如果要其结果缩进可以指定值为Indented,下图是不缩进和缩进的对比。

image

图1:不缩进

image

图2:缩进

模型绑定

Web API中模型绑定非常类似于MVC,分模型验证和参数绑定两个阶段。

1.模型验证

当接受到一个请求时,通常需要对其数据进行验证,验证通过后才进行处理。我们可以使用Web API内置的验证机制来实现,包括数据注解和错误处理。

①数据注解

可以使用命名空间System.ComponentModel.DataAnnotations下的特性来标注,比如我希望模型Contact的FirstName不能为null,加上特性Required即可,如下图。

image

②错误处理

假设我要往服务端插入一条新记录,客户端发送请求POST api/contact/addcontact,请求的JSON数据如下图。

image

服务端action代码如下

image

通过调试会发现,模型绑定后FirstName为null,所以ModelState.IsValid返回false,如下图。

image

图1:FirstName为null

image

图2:服务端返回的内容

上面我们是在action内部做的验证和错误处理,实际上,我们可以通过创建一个filter,在调用action之前就进行验证和错误处理,步骤如下。

①定义filter,如图1

②应用filter,有两种方式,一是刚定义的filter实例加到HttpConfiguration.Filters集合中,如图2。二是在Controller或Action上应用特性,如图3。

image

图1:定义filter

image

图2:将filter加到HttpConfiguration.Filters中

image

图3:在Action上应用filter

2.参数绑定

默认情况下,有两种类型的绑定参数,简单类型(见备注)和自定义类型。对于简单类型,Web API会从URI(包括querystring和route data)中取值;对于自定义类型,Web API会从请求体(request body)中取值。

注:简单类型,即常见的string,int,bool,datetime等以及能转换成string的类型。

①简单类型绑定

对于简单类型Web API会从route data或query string中取值,如下图。

GET api/Contact/SearchContactById/001 //route data

GET api/Contact/SearchContactById?id=001 //query string

这两个uri都能映射到这个action:

image

②自定义类型绑定

对于自定义类型Web API会从request body中取值,示例代码如下。

Request:

image

Action:

image

Response:

收到415的错误,错误信息如下图。

image

image

错误日志已经明确告诉我们是由于没有在request header中指定content-type造成的,这里会引申另一个知识点,Web API中的内容协商。简单来说就是,客户端告诉服务端返回什么格式的数据,然后服务端按客户端的要求返回相应格式数据的过程。通常,客户端会在请求头中指定需要的格式,主要的选项如下。

a.Accept:可接受的媒体类型,如application/json,application/xml等

b.Accept-Charset:可接受的字符集,如UTF-8,ISO 8859-1等

c.Accept-Encoding:可接收的内容编码,如“gzip”。

d.Accept-Language:优先选用的自然语言,如“en-us”。

了解了内容协商后,我们知道需要在请求头中指定content-type的值。

Accept指定response body的格式,而Content-Type指定request body的格式,如果没有指定Accept,则使用Content-Type的格式。

客户端请求:

image

服务端响应:HTTP/1.1 200 OK

③定制参数绑定

我们可以改变Web API默认的参数绑定行为,如果要从URI中读取自定义类型,可以使用特性FromUri,如图1;如果要从request body中读取简单类型,可以使用特性FromBody,如图2。

image

图1

请求URI:GET http://localhost.dev.wingontravel.com/HWARestAPI/api/Contact/SearchContact?id=001&FirstName=san&LastName=zhang

image

图2

请求如下图

image

需要注意的是:FromUri可以被标注多次,但是FromBody只能被标注一次。

原文地址:https://www.cnblogs.com/mcgrady/p/4701934.html