前言

阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html

本文描述ASP.NET Web API中的JSON和XML格式化器。

在ASP.NET Web API中,媒体类型格式化器(Media-type Formatter)是一种能够做以下工作的对象:

  • 从HTTP消息体读取CLR(公共语言运行时)对象
  • 将CLR对象写入HTTP消息体

Web API提供了用于JSON和XML的媒体类型格式化器。框架已默认将这些格式化器插入到消息处理管线之中。客户端在HTTP请求的Accept报头中可以请求JSON或XML。

JSON媒体类型格式化器

JSON格式化是由JsonMediaTypeFormatter类提供的。默认情况下,JsonMediaTypeFormatter使用Json.NET库执行序列化工作。Json.NET是一个第三方开源项目。

如果喜欢,你可以将JsonMediaTypeFormatter配置成使用DataContractJsonSerializer来代替Json.NET。要想这么做,只需UseDataContractJsonSerializer将属性设置为true即可:

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.UseDataContractJsonSerializer = true;

JSON序列化

本小节描述,在使用默认的Json.NET序列化器时,JSON格式化器的一些特定行为。这并不意味着要包含Json.NET库的整个文档。更多信息参阅Json.NET Documentation。

什么会被序列化?

默认情况下,所有public属性和字段都会被包含在序列化的JSON中。为了忽略一个属性或字段,需要用JsonIgnore注解属性修饰它。

public class Product
{
public string Name { get; set; }
public decimal Price { get; set; } [JsonIgnore]
public int ProductCode { get; set; } // omitted
}

如果你更喜欢“opt-in(选入)”方法,可以用DataContract注解属性来修饰类。如果有注解属性,则成员均被忽略,除非有DataMemberDataMember也可以序列化private成员。

[DataContract]
public class Product
{
[DataMember]
public string Name { get; set; } [DataMember]
public decimal Price { get; set; }
public int ProductCode { get; set; } // omitted by default
}

只读属性

只读属性默认是序列化的。

Dates(日期)

默认情况下,Json.NET会将日期写成ISO 8601格式。UTC(Coordinated Universal Time — 世界标准时间)格式的日期书写时带有后缀“Z”。本地时间格式的日期包括了一个时区偏移量。例如:

--27T18::.53403Z         // UTC(标准时间)
--27T11::45.53403-: // Local(本地时间)

默认情况下,Json.NET保留时区。通过设置DateTimeZoneHandling属性,可以重写这一行为:

// Convert all dates to UTC
// 将所有日期转换成UTC格式
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.DateTimeZoneHandling =
Newtonsoft.Json.DateTimeZoneHandling.Utc;

如果你喜欢使用微软的JSON日期格式("\/Date(ticks)\/ ")而不是ISO 8601,可以在SerializerSettings上设置DateFormatHandling属性:

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.DateFormatHandling =
Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat;

Indenting(缩进)

为了书写有缩进的JSON,可以将Formatting设置为Formatting.Indented

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.Formatting =
Newtonsoft.Json.Formatting.Indented;

Camel Casing(驼峰式大小写转换)

为了在不修改数据模型的情况下,用驼峰式大小写转换JSON的属性名,可以设置序列化器上的CamelCasePropertyNamesContractResolver

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.ContractResolver =
new CamelCasePropertyNamesContractResolver();

匿名类型与弱类型对象

动作方法或以返回一个匿名对象,并将其序列化成JSON。例如:

public object Get()
{
return new {
Name = "Alice",
Age = ,
Pets = new List<string> { "Fido", "Polly", "Spot" }
};
}

响应消息体将含有以下JSON:

{"Name":"Alice","Age":,"Pets":["Fido","Polly","Spot"]}

如果Web API从客户端接收了松散结构的JSON,你可以将该请求体解序列化成Newtonsoft.Json.Linq.JObject类型。

public void Post(JObject person)
{
string name = person["Name"].ToString();
int age = person["Age"].ToObject<int>();
}

然而,通常更好的是使用强类型数据对象。那么,便不需要自行对数据进行解析,并且能得到模型验证的好处。

XML序列化器不支持匿名类型或JObject实例。如果将这些特性用于JSON数据,应该去掉管线中的XML格式化器,如本文稍后描述的那样。

XML媒体类型格式化器

  XML格式化是由XmlMediaTypeFormatter类提供的。默认情况下,XmlMediaTypeFormatter使用DataContractSerializer类来执行序列化。如果喜欢,你可以将XmlMediaTypeFormatter配置成使用XmlSerializer而不是DataContractSerializer。要想这么做,可将UseXmlSerializer属性设置为true: 

var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xml.UseXmlSerializer = true;

XmlSerializer类支持的类型集要比DataContractSerializer更窄一些,但对结果XML有更多的控制。如果需要与已有的XML方案匹配,可考虑使用XmlSerializer

XML Serialization——XML序列化

本小节描述使用默认DataContractSerializer的时,XML格式化器的一些特殊行为。默认情况下,DataContractSerializer行为如下:

  •   序列化所有public读/写属性和字段。为了忽略一个属性或字段,请用IgnoreDataMember注解属性修饰它。
  •   private和protected成员不作序列。
  •   只读属性不作序列化
  •   类名和成员名按类声明中的确切呈现写入XML
  •   使用XML的默认命名空间

如果需要在序列化上的更多控制,可以用DataContract注解属性修饰类。当这个注解属性出现时,该类按以策略序列化:

  •   “Opt in(选入)”方法:属性与字段默认不被序列化。为了序列化一个属性或字段,请用DataMember注解属性修饰它。
  •   要序列化private或protected成员,请用DataMember注解属性修饰它。
  •   只读属性不被序列化。
  •   要改变类名在XML中的呈现,请在DataContract注解属性中设置Name参数。
  •   要改变成员名在XML中的呈现,请设置DataMember注解属性中的Nmae参数。
  •   要改变XML命名空间,请设置DataContract类中的Namespace参数。

Read-Only Properties——只读属性

只读属性是不被序列化的。如果只读属性有一个支撑private字段,可以用DataMember注解属性对这个private字段进行标记。这种办法需要在类上使用DataContract注解属性。

[DataContract]
public class Product
{
[DataMember]
private int pcode; // serialized(序列化的) // Not serialized (read-only)
// 不作序列化(只读)
public int ProductCode { get { return pcode; } }
}

Dates——日期

日期被写成ISO 8601格式。例如,“2012-05-23T20:21:37.9116538Z”。

Indenting——缩进

要书写缩进的XML,请将Indent属性设置为true

var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xml.Indent = true;

设置每一类型(Per-Type)的XML序列化器

你可以为不同的CLR类型设置不同的XML序列化器。例如,你可能有一个特殊的数据对象,它出于向后兼容而需要XmlSerializer。你可以为此对象使用XmlSerializer,而对其它类型继续使用DataContractSerializer

为了设置用于特殊类型的XML序列化器,要调用SetSerializer

var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
// Use XmlSerializer for instances of type "Product":
// 对“Product”类型的实例使用XmlSerializer:
xml.SetSerializer<Product>(new XmlSerializer(typeof(Product)));

你可以指定一个XmlSerializer,或任何派生于XmlObjectSerializer的对象。

Removing the JSON or XML Formatter——去除JSON或XML格式化器

你可以从格式化器列表中删除JSON格式化器,或XML格式化器,只要你不想使用它们。这么做的主要原因是:

  •   将你的Web API响应限制到特定的媒体类型。例如,你可能决定只支持JSON响应,而删除XML格式化器。
  •   用一个自定义格式化器代替默认的格式化器。例如,你可能要用自己的自定义JSON格式化器实现来代替(默认的)JSON格式化器。

以下代码演示了如何删除默认的格式化器。在Global.asax中定义的Application_Start方法中调用它。

void ConfigureApi(HttpConfiguration config)
{
// Remove the JSON formatter
// 删除JSON格式化器
config.Formatters.Remove(config.Formatters.JsonFormatter); // or(或者) // Remove the XML formatter
// 删除XML格式化器
config.Formatters.Remove(config.Formatters.XmlFormatter);
}

Handling Circular Object References——处理循环对象引用

在默认情况下,JSON和XML格式化器将所有对象都写成值。如果两个属性引用了同一个对象,或者,如果在一个集合同一个对象出现了两次,格式化器将对此对象做两次序列化。这是在对象图含有循环的情况下会出现的特有问题,因为,序列化器在检测到对象图中的循环时,会抛出异常。

考虑以下对象模型和控制器。

public class Employee
{
public string Name { get; set; }
public Department Department { get; set; }
} public class Department
{
public string Name { get; set; }
public Employee Manager { get; set; }
} public class DepartmentsController : ApiController
{
public Department Get(int id)
{
Department sales = new Department() { Name = "Sales" };
Employee alice = new Employee() { Name = "Alice", Department = sales };
sales.Manager = alice;
return sales;
}
}

调用此动作会触发格式化器抛出异常,该异常将转换成发送给客户端的状态代码500(内部服务器错误)响应。

为了保留JSON中的对象引用,对Global.asax文件的Application_Start方法添加以下代码:

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling =
Newtonsoft.Json.PreserveReferencesHandling.All;

现在,此控制器动作将返回类似于如下形式的JSON:

{"$id":"","Name":"Sales","Manager":{"$id":"","Name":"Alice","Department":{"$ref":""}}}

注意,序列化器对两个对象都添加了一个“$id”。而且,它检测到Employee.Department属性产生了一个循环,因此,它用一个对象引用{"$ref":"1"}代替这个值。

对象引用是不标准的JSON。在使用此特性之前,要考虑你的客户端是否能够解析这种结果。简单地去除对象图中的循环,可能是更好的办法。例如,此例中Employee链接回Department并不是真正的需要。

为了保留XML中的对象引用,可以使用两个选项。较简单的选项是对模型类添加[DataContract(IsReference=true)]。IsReference参数启用了对象引用。记住,DataContract构成了序列化的“选入(Opt-in)”,因此,你还需要对属性添加DataMember注解属性:

[DataContract(IsReference=true)]
public class Department
{
[DataMember]
public string Name { get; set; } [DataMember]
public Employee Manager { get; set; }
}

现在,该格式化器将产生类似于如下形式的XML:

<Department xmlns:i="http://www.w3.org/2001/XMLSchema-instance" z:Id="i1"
xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/"
xmlns="http://schemas.datacontract.org/2004/07/Models">
<Manager>
<Department z:Ref="i1" />
<Name>Alice</Name>
</Manager>
<Name>Sales</Name>
</Department>

如果想避免在模型类上使用注解属性,还有另一个选项:创建新的类型专用的DataContractSerializer实例,并在构造器中将preserveObjectReferences设置为true

var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
var dcs = new DataContractSerializer(typeof(Department), null, int.MaxValue,
false, /* preserveObjectReferences: */ true, null);
xml.SetSerializer<Department>(dcs);

Testing Object Serialization——测试对象序列化

在设计Web API时,对如何序列化对象进行测试是有用的。不必创建控制器或调用控制器动作,便可做这种事。

string Serialize<T>(MediaTypeFormatter formatter, T value)
{
// Create a dummy HTTP Content.
// 创建一个HTTP内容的哑元
Stream stream = new MemoryStream();
var content = new StreamContent(stream); // Serialize the object.
// 序列化对象
formatter.WriteToStreamAsync(typeof(T), value, stream, content.Headers, null).Wait(); // Read the serialized string.
// 读取序列化的字符串
stream.Position = ;
return content.ReadAsStringAsync().Result;
} T Deserialize<T>(MediaTypeFormatter formatter, string str) where T : class
{
// Write the serialized string to a memory stream.
// 将序列化的字符器写入内在流
Stream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(str);
writer.Flush();
stream.Position = ; // Deserialize to an object of type T
// 解序列化成类型为T的对象
return formatter.ReadFromStreamAsync(typeof(T), stream, null, null).Result as T;
} // Example of use
// 使用示例(用例)
void TestSerialization()
{
var value = new Person() { Name = "Alice", Age = }; var xml = new XmlMediaTypeFormatter();
string str = Serialize(xml, value); var json = new JsonMediaTypeFormatter();
str = Serialize(json, value); // Round trip
// 反向操作(解序列化)
Person person2 = Deserialize<Person>(json, str);
}

总结

本课主要简单的了解一下JSON和XML的序列化和反序列的使用。

本文的参考链接为 http://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization

同时本文已更新至 Web API导航系列 http://www.cnblogs.com/aehyok/p/3446289.html

Asp.Net Web API 2第十三课——ASP.NET Web API中的JSON和XML序列化的更多相关文章

  1. ASP.NET Web API中的JSON和XML序列化

    ASP.NET Web API中的JSON和XML序列化 前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok ...

  2. 【ASP.NET Web API教程】6.2 ASP.NET Web API中的JSON和XML序列化

    谨以此文感谢关注此系列文章的园友!前段时间本以为此系列文章已没多少人关注,而不打算继续下去了.因为文章贴出来之后,看的人似乎不多,也很少有人对这些文章发表评论,而且几乎无人给予“推荐”.但前几天有人询 ...

  3. JAVA学习第三十三课(经常使用对象API) —迭代器

    数字有非常多用数组存,对象有非常多就要用集合存 可是数组是固定长度的,集合是可变长度的 集合的由来: 对象用来封装特有数据,对象多了须要存储,假设对象个数不确定,就须要使用集合容器来存储 集合的特点: ...

  4. Kali Linux Web 渗透测试视频教程— 第十三课-密码破解

    Kali Linux Web 渗透测试— 第十三课-密码破解 文/玄魂 目录 Kali Linux Web 渗透测试— 第十三课-密码破解............................... ...

  5. 【ASP.NET MVC 学习笔记】- 19 REST和RESTful Web API

    本文参考:http://www.cnblogs.com/willick/p/3441432.html 1.目前使用Web服务的三种主流的方式是:远程过程调用(RPC),面向服务架构(SOA)以及表征性 ...

  6. Asp.Net Web API 2第十一课——在Web API中使用Dependency Resolver

    前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html 本文主要来介绍在Asp.N ...

  7. Asp.Net Web API 2(入门)第一课

    Asp.Net Web API 2(入门)第一课   前言 Http不仅仅服务于Web Pages.它也是一个创建展示服务和数据的API的强大平台.Http是简单的.灵活的.无处不在的.你能想象到几乎 ...

  8. Asp.Net Web API 2第九课——自承载Web API

    前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html Asp.Net Web A ...

  9. Asp.Net Web API 2第八课——Web API 2中的属性路由

    前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html 路由就是Web API如何 ...

随机推荐

  1. apache相关

    http://hw1287789687.iteye.com/blog/2212292 http://enable-cors.org/server_apache.html http://blog.sin ...

  2. exports 和 module.exports 的区别

    https://cnodejs.org/topic/5231a630101e574521e45ef8 //一句话总结:exports是对module.exports的引用,require()返回的是 ...

  3. 移动端调试工具-Weinre

    java版本安装和调试 首先需要下载 weinre, weinre目前支持Windows与MacOS, 本文中以Windows版为例. 下载地址:http://people.apache.org/~p ...

  4. LINUX内核分析第七周学习总结:可执行程序的装载

    LINUX内核分析第七周学习总结:可执行程序的装载 韩玉琪 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/cours ...

  5. 在线学习体验大PK 云智慧发布在线教育网站性能监测报告

    互联网不但改变了我们的生活.娱乐和消费方式,也推动各行各业进行着快速变革,越来越多的职场人士必须通过不断的学习.充电才能跟上行业发展的步伐,获得职业的提升,而这也引发了国内教育市场的爆炸式发展.据统计 ...

  6. solr入门命令

    #####################shell命令############################# 导入文档: sh bin/post -c gettingstarted docs/i ...

  7. MySql表名的大小写问题

    MySQL在Linux下数据库名.表名.列名.别名大小写规则是这样的: 1.数据库名与表名是严格区分大小写的: 2.表的别名是严格区分大小写的: 3.列名与列的别名在所有的情况下均是忽略大小写的: 4 ...

  8. Java学习笔记15--引用传递

    范例一 class Demo{ public int temp = 30; } public class T { public static void main(String[] args) { // ...

  9. 单片机TM4C123学习(九):PWM

    1.头文件与变量定义 #include "tiva_pwm.h" // PWM 2.初始化 // PWM 初始化,频率为1000,占空比为0 M1PWM7_init(, ); // ...

  10. js判断用户是否禁用了cookie

    function CookieEnable() { var result = false; if (navigator.cookiesEnabled) return true; document.co ...