在 .NET Framework 中使用 JSON

JSON 文本可依据 JavaScript 代码轻松地进行创建和分析,这是它的一个吸引人之处。但是,当 JSON 用于 ASP.NET web 应用程序时,只有浏览器受 JavaScript 支持,因为服务器端代码很可能是用 Visual Basic 或 C# 编写的。

大多数为 ASP.NET 设计的 Ajax 库都支持以编程方式创建和分析 JSON 文本。因此,要在 .NET 应用程序中使用 JSON,请考虑使用其中一个库。有众多的开源和第三方方案可供选择,而 Microsoft 也有自己的 Ajax 库,名为 ASP.NET AJAX。

在本文中,我们会介绍使用 Jayrock 的示例,它是一种用于 Microsoft .NET Framework 的 JSON 开源实现,由合著者 Atif Aziz 创建。我们选择使用 Jayrock 而非 ASP.NET AJAX 的原因有三个:

  • Jayrock 是开源的,可以按需要扩展或自定义。
  • Jayrock 可用于 ASP.NET 1.x,、2.0 和 Mono 应用程序,而 ASP.NET AJAX 仅限于 ASP.NET 2.0 版。
  • Jayrock 的作用域仅限于 JSON 和 JSON-RPC,前者是本文的重点内容。ASP.NET AJAX 包括对创建和分析 JSON 文本的一些支持,但它的主要用途是提供一个丰富的平台,在 ASP.NET 中构建端到端 Ajax 风格的 web 应用程序。您的重点内容为 JSON 时,额外的点缀性功能反而会让人分神。

在 .NET 中通过 Jayrock 使用 JSON,与在 .NET Framework 中通过 XmlWriter、XmlReader 和 XmlSerializer 类使用 XML 相似。位于 Jayrock 中的类 JsonWriterJsonReaderJsonTextWriterJsonTextReader 模拟 .NET Framework 类 XmlWriterXmlReaderXmlTextWriterXmlTextReader 的语义。这些类在低级别和面向流的级别与 JSON 交互时非常有用。使用这些类,可通过一系列的方法调用逐个创建或分析 JSON 文本。例如,使用 JsonWriter 类方法 WriteNumber(number) 可根据 JSON 标准写出适当的“数字”形式的字符串表示形式。JsonConvert 类提供了用于在 .NET 类型和 JSON 之间进行转换的 ExportImport 方法。这些方法提供了分别与 XmlSerializer 类方法 SerializeDeserialize 相似的功能。

创建 JSON 文本

以下代码说明了如何使用 JsonTextWriter 类来创建洲字符串数组的 JSON 文本。此 JSON 文本会发送到传入构造函数的 TextWriter 实例,在此示例中正好是来自控制台的输出流(在 ASP.NET 中您可以使用 Response.Output):

using (JsonTextWriter writer = JsonTextWriter(Console.Out)){ writer.WriteStartArray(); writer.WriteString("Europe"); writer.WriteString("Asia"); writer.WriteString("Australia"); writer.WriteString("Antarctica"); writer.WriteString("North America"); writer.WriteString("South America"); writer.WriteString("Africa"); writer.WriteEndArray();}

除了 WriteStartArrayWriteStringWriteEndArray 方法之外,JsonWriter 类还提供了用于编写其他 JSON 值类型的方法,如 WriteNumberWriteBooleanWriteNull 等。WriteStartObjectWriteEndObjectWriteMember 方法为对象创建 JSON 文本。以下示例说明了如何为“了解 JavaScript 中的文字表示法”部分探讨的联系对象创建 JSON 文本:

private static void WriteContact(){ using (JsonWriter writer = new JsonTextWriter(Console.Out)) { writer.WriteStartObject(); // { writer.WriteMember("Name"); // "Name" : writer.WriteString("John Doe"); // "John Doe", writer.WriteMember("PermissionToCall"); // "PermissionToCall" : writer.WriteBoolean(true); // true, writer.WriteMember("PhoneNumbers"); // "PhoneNumbers" : writer.WriteStartArray(); // [ WritePhoneNumber(writer, // { "Location": "Home", "Home", "555-555-1234"); // "Number": "555-555-1234" }, WritePhoneNumber(writer, // { "Location": "Work", "Work", "555-555-9999 Ext. 123"); // "Number": "555-555-9999 Ext. 123" } writer.WriteEndArray(); // ] writer.WriteEndObject(); // } }}private static void WritePhoneNumber(JsonWriter writer, string location, string number){ writer.WriteStartObject(); // { writer.WriteMember("Location"); // "Location" : writer.WriteString(location); // "...", writer.WriteMember("Number"); // "Number" : writer.WriteString(number); // "..." writer.WriteEndObject(); // }}

JsonConvert 类中的 ExportExportToString 方法可用于将指定的 .NET 类型序列化为 JSON 文本。例如,不需要使用 JsonTextWriter 类为七大洲数组手动构建 JSON 文本,以下对 JsonConvert.ExportToString 的调用即可产生相同的结果:

string[] continents = {      "Europe", "Asia", "Australia", "Antarctica", "North America", "South America", "Africa"};string jsonText = JsonConvert.ExportToString(continents);

分析 JSON 文本

JsonTextReader 类提供了各种分析 JSON 文本令牌的方法,其中核心的一种是 Read。每次调用 Read 方法时,分析器会使用下一个令牌,可能是字符串值、数字值、对象成员名称、数组开头等。可能的话,可以通过 Text 属性访问当前令牌的已分析文本。例如,如果该读取器位于 Boolean 数据中,则 Text 属性会根据实际分析值返回“true”或“false”。

以下示例代码使用 JsonTextReader 类,对包含七大洲名称的字符串数组的 JSON 文本表示形式进行分析。每个以字母“A”开头的洲会发送到控制台:

string jsonText = @"["Europe", "Asia", "Australia", "Antarctica", "North America", "South America", "Africa"]";using (JsonTextReader reader = new JsonTextReader(new StringReader(jsonText))){ while (reader.Read()) { if (reader.TokenClass == JsonTokenClass.String & reader.Text.StartsWith("A")) { Console.WriteLine(reader.Text); } }}
注意Jayrock 中的 JsonTextReader 类是一个非常自由的 JSON 文本分析器。它实际上允许的语法要比 RFC 4627 中列出的规则所规定的有效 JSON 文本多得多。例如,就象在 JavaScript 中一样,JsonTextReader 类允许单行和多行注释出现在 JSON 文本内。单行注释以双斜杠 (//) 开头,多行注释以斜杠星号 (/*) 开头,并以星号斜杠 (*/) 结尾。单行注释甚至能以井字号 (#) 开头,这在 Unix 样式的配置文件中十分常见。在所有实例中,分析器会完全跳过注释,不会通过 API 公开。和在 JavaScript 中一样,JsonTextReader 允许以撇号 (') 分隔 JSON 字符串。该分析器甚至可以容忍最后一个对象成员或者数组元素后面多余的逗号。
即使具备所有这些附加内容,JsonTextReader 仍是符合标准的分析器!而 JsonTextWriter 则只能产生严格符合标准的 JSON 文本。这遵循了通常所说的可靠性原则,即“严以律己,宽以待人”。

要将 JSON 文本直接转换为 .NET 对象,请使用 JsonConvert 类导入方法,指定输出类型和 JSON 文本。以下示例显示了从 JSON 字符串数组到 .NET 字符串数组的转换:

string jsonText = @"["Europe", "Asia", "Australia", "Antarctica", "North America", "South America", "Africa"]";string[] continents = (string[]) JsonConvert.Import(typeof(string[]), jsonText);

以下是一个更有意思的转换示例:取得 RSS XML 源,使用 XmlSerializer 将其反序列化为 .NET 类型,然后使用 JsonConvert 将该对象转换为 JSON 文本(将 XML 格式的 RSS 有效转换为 JSON 文本):

XmlSerializer serializer = new XmlSerializer(typeof(RichSiteSummary));RichSiteSummary news;// Get the MSDN RSS feed and deserialize it...using (XmlReader reader = XmlReader.Create("http://msdn.microsoft.com/rss.xml")){ news = (RichSiteSummary) serializer.Deserialize(reader);}// Export the RichSiteSummary object as JSON text, emitting the output to Console.Outusing (JsonTextWriter writer = new JsonTextWriter(Console.Out)){ JsonConvert.Export(news, writer);}
注意 可在本文附带的示例中找到 RichSiteSummary 定义及其相关类型。

参考资料:

http://msdn.microsoft.com/zh-cn/library/bb299886.aspx

Jayrock下载:

http://jayrock.berlios.de/