使用 DataContractJsonSerializer 的独立 JSON 序列化Stand-Alone JSON Serialization using DataContractJsonSerializer

备注

本文介绍 DataContractJsonSerializerThis article is about DataContractJsonSerializer. 对于涉及序列化和反序列化 JSON 的大多数方案,我们建议在system.web 命名空间中提供 api。For most scenarios that involve serializing and deserializing JSON, we recommend the APIs in the System.Text.Json namespace.

JSON(JavaScript 对象表示法)是专门为浏览器中的网页上运行的 JavaScript 代码而设计的一种数据格式。JSON (JavaScript Object Notation) is a data format that is specifically designed to be used by JavaScript code running on Web pages inside the browser. 这是 ASP.NET AJAX 服务在 Windows Communication Foundation (WCF)中创建的默认数据格式。It is the default data format used by ASP.NET AJAX services created in Windows Communication Foundation (WCF).

在未与 ASP.NET 集成的情况下(在此情况下,XML 将是默认格式,但可以选择 JSON)创建 AJAX 服务时,也可以使用此格式。This format can also be used when creating AJAX services without integrating with ASP.NET - in this case, XML is the default but JSON can be chosen.

最后,如果需要 JSON 支持但不创建 AJAX 服务,则可以使用 DataContractJsonSerializer,以便将 .NET 对象直接序列化为 JSON 数据并将此类数据反序列化回 .NET 类型的实例。Finally, if you require JSON support but are not creating an AJAX service, the DataContractJsonSerializer makes it possible to directly serialize .NET objects into JSON data and to deserialize such data back into instances of .NET types. 有关如何执行此操作的说明,请参阅如何:对 JSON 数据进行序列化和反序列化。For a description of how to do this, see How to: Serialize and Deserialize JSON Data.

使用 JSON 时,它支持的 .NET 类型与 DataContractSerializer 支持的类型相同,但有少数例外。When working with JSON, the same .NET types are supported, with a few exceptions, as are supported by the DataContractSerializer. 有关支持的类型的列表,请参阅数据协定序列化程序支持的类型For a list of the types supported, see Types Supported by the Data Contract Serializer. 支持的类型包括大多数基元类型、大多数数组和集合类型,以及使用 DataContractAttributeDataMemberAttribute 的复杂类型。This includes most primitive types, most array and collection types, as well as complex types that use the DataContractAttribute and DataMemberAttribute.

将 .NET 类型映射到 JSON 类型Mapping .NET types to JSON Types

下表显示 .NET 类型和 JSON/JavaScript 类型在通过序列化和反序列化过程进行映射时的对应关系。The following table shows the correspondence between .NET types and JSON/JavaScript types when mapped by serialization and deserialization procedures.

.NET 类型.NET Types JSON/JavaScriptJSON/JavaScript 说明Notes
所有数值类型,例如 Int32DecimalDoubleAll numeric types, for example Int32, Decimal or Double 数字Number 不支持 Double.NaNDouble.PositiveInfinityDouble.NegativeInfinity 等特殊值,它们会导致无效的 JSON。Special values such as Double.NaN, Double.PositiveInfinity and Double.NegativeInfinity are not supported and result in invalid JSON.
Enum 数字Number 请参见本主题中后面的“枚举和 JSON”。See "Enumerations and JSON" later in this topic.
Boolean 布尔Boolean --
String, CharString, Char StringString --
TimeSpan, Guid, UriTimeSpan, Guid, Uri StringString JSON 中的这些类型的格式与 XML 中的格式相同(实质上为时间跨度,格式为 ISO 8601,格式为 "12345678-1234567890AB",格式为 " http://www.example.com ")。The format of these types in JSON is the same as in XML (essentially, TimeSpan in the ISO 8601 Duration format, GUID in the "12345678-ABCD-ABCD-ABCD-1234567890AB" format and URI in its natural string form like "http://www.example.com"). 有关精确信息,请参阅数据协定架构参考For precise information, see Data Contract Schema Reference.
XmlQualifiedName StringString 格式为“名称:命名空间”(第一个冒号之前的所有内容都是名称)。The format is "name:namespace" (anything before the first colon is the name). 可以缺少名称或命名空间。Either the name or the namespace can be missing. 如果没有命名空间,则也可以省略冒号。If there is no namespace the colon can be omitted as well.
Array 类型的 ByteArray of type Byte 数字数组Array of numbers 每个数字都表示一个字节的值。Each number represents the value of one byte.
DateTime DateTime 或 StringDateTime or String 请参见本主题中后面的“日期/时间和 JSON”。See Dates/Times and JSON later in this topic.
DateTimeOffset 复杂类型Complex type 请参见本主题中后面的“日期/时间和 JSON”。See Dates/Times and JSON later in this topic.
XML 和 ADO.NET 类型(XmlElementXML and ADO.NET types (XmlElement,

XElement.XElement. XmlNodeArrays of XmlNode,

ISerializable,ISerializable,

DataSet).DataSet).
StringString 请参见本主题的“XML 类型和 JSON”一节。See the XML Types and JSON section of this topic.
DBNull 空复杂类型Empty complex type --
集合、字典和数组Collections, dictionaries, and arrays ArrayArray 请参见本主题的“集合、字典和数组”一节。See the Collections, Dictionaries, and Arrays section of this topic.
复杂类型(应用了 DataContractAttributeSerializableAttributeComplex types (with the DataContractAttribute or SerializableAttribute applied) 复杂类型Complex type 数据成员变为 JavaScript 复杂类型的成员。Data members become members of the JavaScript complex type.
实现 ISerializable 接口的复杂类型Complex types implementing the ISerializable interface) 复杂类型Complex type 与其他复杂类型相同,但不支持某些 ISerializable 类型(请参见本主题“高级信息”一节的“ISerializable 支持”部分)。Same as other complex types but some ISerializable types are not supported – see the ISerializable Support part of the Advanced Information section of this topic.
任何类型的 NullNull value for any type NullNull 也支持可以为 null 的值类型,并以与不可以为 null 的值类型相同的方式映射到 JSON。Nullable value types are also supported and map to JSON in the same way as non-nullable value types.

枚举和 JSONEnumerations and JSON

在 JSON 中,枚举成员值被作为数字处理,这与数据协定中处理枚举成员值的方式不同。在数据协定中,枚举成员值被视为成员名称。Enumeration member values are treated as numbers in JSON, which is different from how they are treated in data contracts, where they are included as member names. 有关数据协定处理的详细信息,请参阅数据协定中的枚举类型For more information about the data contract treatment, see Enumeration Types in Data Contracts.

  • 例如,如果存在 public enum Color {red, green, blue, yellow, pink},则序列化 yellow 将生成数字 3,而不是字符串“yellow”。For example, if you have public enum Color {red, green, blue, yellow, pink}, serializing yellow produces the number 3 and not the string "yellow".

  • 所有 enum 成员都是可序列化的。All enum members are serializable. 如果使用了 EnumMemberAttributeNonSerializedAttribute 属性,则忽略它们。The EnumMemberAttribute and the NonSerializedAttribute attributes are ignored if used.

  • 可以反序列化不存在的 enum 值。例如,可以将值 87 反序列化为上面的颜色枚举,尽管并未定义相应的颜色名称。It is possible to deserialize a nonexistent enum value - for example, the value 87 can be deserialized into the previous Color enum even though there is no corresponding color name defined.

  • 标志 enum 并不特殊,其处理方式与任何其他 enum 相同。A flags enum is not special and is treated the same as any other enum.

日期/时间和 JSONDates/Times and JSON

JSON 格式不直接支持日期和时间。The JSON format does not directly support dates and times. 但是,由于这些类型十分常用,因此 ASP.NET AJAX 对它们提供了特殊的支持。However, they are very commonly used and ASP.NET AJAX provides special support for these types. 使用 ASP.NET AJAX 代理时,.NET 中的 DateTime 类型与 JavaScript 中的 DateTime 类型完全对应。When using ASP.NET AJAX proxies, the DateTime type in .NET fully corresponds to the DateTime type in JavaScript.

  • 当不使用 ASP.NET 时,DateTime 类型在 JSON 中将表示为一个具有特殊格式的字符串。本主题的“高级信息”一节中对这种特殊格式进行了描述。When not using ASP.NET, a DateTime type is represented in JSON as a string with a special format that is described in the Advanced Information section of this topic.

  • DateTimeOffset 在 JSON 中以复杂类型表示:{"DateTime":dateTime,"OffsetMinutes":offsetMinutes}。DateTimeOffset is represented in JSON as a complex type: {"DateTime":dateTime,"OffsetMinutes":offsetMinutes}. offsetMinutes 成员是与相关事件所在位置关联的本地时间与格林威治标准时间 (GMT)(现在也称为协调世界时 (UTC))之间的偏移量。The offsetMinutes member is the local time offset from Greenwich Mean Time (GMT), also now referred to as Coordinated Universal Time (UTC), associated with the location of the event of interest. dateTime 成员表示发生相关事件时的时间实例(同样,当使用 ASP.NET AJAX 时,它将变为 JavaScript 中的 DateTime;不使用 ASP.NET AJAX 时,它将变为字符串)。The dateTime member represents the instance in time when the event of interest occurred (again, it becomes a DateTime in JavaScript when ASP.NET AJAX is in use and a string when it is not). dateTime 成员始终用 GMT 格式进行序列化。On serialization, the dateTime member is always serialized in GMT. 因此,如果描述纽约时间凌晨 3:00,dateTime 的时间部分将是上午 8:00,而 offsetMinutes 是 300(从 GMT 中减去 300 分钟或 5 个小时)。So, if describing 3:00 AM New York time, dateTime has a time component of 8:00 AM and offsetMinutes are 300 (minus 300 minutes or 5 hours from GMT).

    备注

    在将 DateTimeDateTimeOffset 对象序列化为 JSON 时,它们保留的信息精度仅为毫秒。DateTime and DateTimeOffset objects, when serialized to JSON, only preserve information to millisecond precision. 在序列化期间,次于毫秒的值(微秒/毫微秒)将丢失。Sub-millisecond values (micro/nanoseconds) are lost during serialization.

XML 类型和 JSONXML Types and JSON

XML 类型成为 JSON 字符串。XML types become JSON strings.

  • 例如,如果 System.xml.linq.xelement> 类型的数据成员 "q" 包含 <abc/> ,则 JSON 为 {"q": " <abc/> "}。For example, if a data member "q" of type XElement contains <abc/>, the JSON is {"q":"<abc/>"}.

  • 有一些特殊的规则来指定如何包装 XML。有关更多信息,请参见本主题后面的“高级信息”一节。There are some special rules that specify how XML is wrapped - for more information, see the Advanced Information section later in this topic.

  • 使用 ASP.NET AJAX 时,如果不希望使用 JavaScript 中的字符串,而是想改用 XML DOM,请在 ResponseFormat 上将 WebGetAttribute 属性设置为 XML,或者在 ResponseFormat 上将 WebInvokeAttribute 属性设置为 XML。If you are using ASP.NET AJAX and do not want to use strings in the JavaScript, but want the XML DOM instead, set the ResponseFormat property to XML on WebGetAttribute or the ResponseFormat property to XML on the WebInvokeAttribute.

集合、字典和数组Collections, Dictionaries and Arrays

在 JSON 中,所有的集合、字典和数组都表示为数组。All collections, dictionaries, and arrays are represented in JSON as arrays.

  • 在 JSON 表示中,忽略使用 CollectionDataContractAttribute 的任何自定义。Any customization that uses the CollectionDataContractAttribute is ignored in the JSON representation.

  • 词典不能直接用于 JSON。Dictionaries are not a way to work directly with JSON. 在 <string,object> WCF 中,可能不会像预期那样支持字典,因为使用其他 JSON 技术。Dictionary<string,object> may not be supported in the same way in WCF as expected from working with other JSON technologies. 例如,在字典中,如果“abc”映射到“xyz”,且“def”映射到 42,则 JSON 表示形式不是 {"abc":"xyz","def":42},而是 [{"Key":"abc","Value":"xyz"},{"Key":"def","Value":42}]。For example, if "abc" is mapped to "xyz" and "def" is mapped to 42 in a dictionary, the JSON representation is not {"abc":"xyz","def":42} but is [{"Key":"abc","Value":"xyz"},{"Key":"def","Value":42}] instead.

  • 如果想要直接使用 JSON(动态访问键和值,而不预定义严格的协定),您有下面几个选择:If you would like to work with JSON directly (accessing keys and values dynamically, without pre-defining a rigid contract), you have several options:

    • 请考虑使用弱类型 JSON 序列化(AJAX)示例。Consider using the Weakly-typed JSON Serialization (AJAX) sample.

    • 请考虑使用 ISerializable 接口和反序列化构造函数。这两个机制允许分别访问序列化和反序列化时的 JSON 键/值对,但不能用于部分受信任的方案。Consider using the ISerializable interface and deserialization constructors - these two mechanisms allow you to access JSON key/value pairs on serialization and deserialization respectively, but do not work in partial trust scenarios.

    • 请考虑使用JSON 和 XML 之间的映射,而不是使用序列化程序。Consider working with the Mapping Between JSON and XML instead of using a serializer.

    • 序列化上下文中的多态性指的是在需要其基类型的情况下序列化派生类型的能力。Polymorphism in the context of serialization refers to the ability to serialize a derived type where its base type is expected. 在以多态形式使用集合时(例如,在将集合分配给 Object 时),有一些 JSON 特定的特殊规则。There are special JSON-specific rules when using collections polymorphically, when, for example, assigning a collection to an Object. 有关此问题的更多详细讨论,请参见本主题后面的“高级信息”一节。This issue is more fully discussed in the Advanced Information section later in this topic.

更多详细信息Additional Details

数据成员的顺序Order of Data Members

使用 JSON 时数据成员的顺序并不重要。Order of data members is not important when using JSON. 具体而言,即使设置了 Order,也仍然可以按任意顺序反序列化 JSON 数据。Specifically, even if Order is set, JSON data can still be deserialized in any order.

JSON 类型JSON Types

JSON 类型在反序列化时并不一定要与上面的表匹配。The JSON type does not have to match the preceding table on deserialization. 例如,Int 通常映射到 JSON 数字,但只要 JSON 字符串中包含有效的数字,就可以成功地从该字符串反序列化到此类型。For example, an Int normally maps to a JSON number, but it can also be successfully deserialized from a JSON string as long as that string contains a valid number. 即,如果存在名为“q”的 Int 数据成员,则 {"q":42} 和 {"q":"42"} 都是有效的。That is, both {"q":42} and {"q":"42"} are valid if there is an Int data member called "q".

多形性Polymorphism

多态序列化具备在需要基类型时序列化派生类型的能力。Polymorphic serialization consists of the ability to serialize a derived type where its base type is expected. WCF 可以通过 WCF 与支持 XML 序列化的方式进行 JSON 序列化。This is supported for JSON serialization by WCF comparable to the way XML serialization is supported. 例如,可以序列化 MyDerivedType 预期位置 MyBaseType ,或序列化 Int 预期位置 ObjectFor example, you can serialize MyDerivedType where MyBaseType is expected, or serialize Int where Object is expected.

需要基类型时,反序列化派生类型可能会丢失类型信息,除非反序列化复杂类型。Type information may be lost when deserializing a derived type if the base type is expected, unless you are deserializing a complex type. 例如,如果在需要 Uri 时序列化 Object,将导致一个 JSON 字符串。For example, if Uri is serialized where Object is expected, it results in a JSON string. 如果随后将此字符串反序列化回 Object,将返回一个 .NET StringIf this string is then deserialized back into Object, a .NET String is returned. 反序列化程序并不知道该字符串最初属于 Uri 类型。The deserializer does not know that the string was initially of type Uri. 通常情况下,在需要 Object 时,所有的 JSON 字符串都将反序列化为 .NET 字符串,并且用于序列化 .NET 集合、字典和数组的所有 JSON 数组都将反序列化为 Array 类型的 .NET Object,而不考虑实际的原始类型。Generally, when expecting Object, all JSON strings are deserialized as .NET strings, and all JSON arrays used to serialize .NET collections, dictionaries, and arrays are deserialized as .NET Array of type Object, regardless of what the actual original type had been. JSON 布尔值映射到 .NET BooleanA JSON boolean maps to a .NET Boolean. 但是,在需要 Object 时,JSON 数字将反序列化为 .NET Int32DecimalDouble,将根据具体情况自动选择最适合的类型。However when expecting an Object, JSON numbers are deserialized as either .NET Int32, Decimal or Double, where the most appropriate type is automatically picked.

反序列化为接口类型时,DataContractJsonSerializer 会将声明的类型作为对象进行反序列化。When deserializing into an interface type, the DataContractJsonSerializer deserializes as if the declared type were object.

在处理自己的基类型和派生类型时,通常需要使用 KnownTypeAttributeServiceKnownTypeAttribute 或与之等效的机制。When working with your own base and derived types, using the KnownTypeAttribute, ServiceKnownTypeAttribute or an equivalent mechanism is normally required. 例如,如果你有一个具有返回值的操作, Animal 并且该操作实际返回的实例 Cat (派生自 Animal ),则应将、应用 KnownTypeAttributeAnimal 类型或 ServiceKnownTypeAttribute 操作,并 Cat 在这些特性中指定类型。For example, if you have an operation that has an Animal return value and it actually returns an instance of Cat (derived from Animal), you should either apply the KnownTypeAttribute, to the Animal type or the ServiceKnownTypeAttribute to the operation and specify the Cat type in these attributes. 有关详细信息,请参阅数据协定已知类型For more information, see Data Contract Known Types.

有关多态序列化工作方式的详细信息,以及使用多态序列化时必须遵从的部分限制的讨论,请参见本主题后面的“高级信息”一节。For details of how polymorphic serialization works and a discussion of some of the limitations that must be respected when using it, see the Advanced Information section later in this topic.

版本管理Versioning

JSON 中完全支持数据协定版本管理功能,其中包括 IExtensibleDataObject 接口。The data contract versioning features, including the IExtensibleDataObject interface, are fully supported in JSON. 不仅如此,在多数情况下还可以将一个类型反序列化为一种格式(例如 XML),然后再将其序列化为另一种格式(例如 JSON),同时仍然保留 IExtensibleDataObject 中的数据。Furthermore, in most cases it is possible to deserialize a type in one format (for example, XML) and then serialize it into another format (for example, JSON) and still preserve the data in IExtensibleDataObject. 有关详细信息,请参阅向前兼容的数据协定For more information, see Forward-Compatible Data Contracts. 请记住,JSON 不进行排序,因此所有顺序信息都将丢失。Remember that JSON is unordered so any order information is lost. 而且,JSON 不支持多个键/值对使用同一键名。Furthermore, JSON does not support multiple key/value pairs with the same key name. 最后,对 IExtensibleDataObject 执行的所有操作在本质上都是多态的,即它们的派生类型均被分配给所有类型的基类型 ObjectFinally, all operations on IExtensibleDataObject are inherently polymorphic - that is their derived type are assigned to Object, the base type for all types.

URL 中的 JSONJSON in URLs

在结合使用 ASP.NET AJAX 终结点与 HTTP GET 谓词(使用 WebGetAttribute 属性)时,传入的参数将出现在请求 URL 而不是消息正文中。When using ASP.NET AJAX endpoints with the HTTP GET verb (using the WebGetAttribute attribute), incoming parameters appear in the request URL instead of the message body. 即使在请求 URL 中,也支持 JSON,因此,如果操作采用名为 " Int number" 的操作和 Person 名为 "p" 的复杂类型,则 url 可能类似于以下 url。JSON is supported even in the request URL, so if you have an operation that takes an Int called "number" and a Person complex type called "p", the URL may resemble the following URL.

http://example.com/myservice.svc/MyOperation?number=7&p={"name":"John","age":42}

如果使用 ASP.NET AJAX 脚本管理器控件和代理调用服务,则此 URL 将由代理自动生成,而不会显示出来。If you are using an ASP.NET AJAX Script Manager control and proxy to call the service, this URL is automatically generated by the proxy and is not seen. JSON 不能用在非 ASP.NET AJAX 终结点上的 URL 中。JSON cannot be used in URLs on non-ASP.NET AJAX endpoints.

高级信息Advanced information

ISerializable 支持ISerializable Support

受支持和不受支持的 ISerializable 类型Supported and Unsupported ISerializable Types

通常情况下,序列化/反序列化 JSON 时完全支持实现 ISerializable 接口的类型。In general, types that implement the ISerializable interface are fully supported when serializing/deserializing JSON. 但是,其中有些类型(包括一些 .NET Framework 类型)采用特殊的实现方式,以致以下 JSON 特定的序列化方面会导致它们不能正确地反序列化:However, some of these types (including some .NET Framework types) are implemented in such a way that the JSON-specific serialization aspects cause them to not deserialize correctly:

  • 使用 ISerializable 时,各个数据成员的类型始终无法提前预知。With ISerializable, the type of individual data members is never known in advance. 这将导致与将类型反序列化为对象时类似的多态情况。This leads to a polymorphic situation similar to deserializing types into an object. 正如前文所述,这在 JSON 中可能会导致类型信息丢失。As mentioned before, this may lead to loss of type information in JSON. 例如,如果某类型在其 enum 实现中序列化一个 ISerializable,则当其尝试直接反序列化回 enum(未执行正确的强制转换)时将失败。这是因为,enum 使用 JSON 中的数字进行序列化,而 JSON 数字却反序列化为内置的 .NET 数值类型(Int32、Decimal 或 Double)。For example, a type that serializes an enum in its ISerializable implementation and attempts to deserialize back directly into an enum (without proper casts) fails, because an enum is serialized using numbers in JSON and JSON numbers deserialize into built-in .NET numeric types (Int32, Decimal or Double). 因此,数字用于 enum 值的事实将丢失。So the fact that the number used to be an enum value is lost.

  • 在反序列化构造函数中依赖特定的反序列化顺序的 ISerializable 类型可能也无法反序列化某些 JSON 数据,因为大多数 JSON 序列化程序并不能保证遵循任何特定的顺序。An ISerializable type that depends on a particular order of deserialization in its deserialization constructor may also fail to deserialize some JSON data, because most JSON serializers do not guarantee any specific order.

工厂类型Factory Types

虽然 JSON 中通常支持 IObjectReference 接口,但它不支持需要“工厂类型”功能(从 GetRealObject(StreamingContext) 中返回与实现接口的类型不同的类型实例)的任何类型。While the IObjectReference interface is supported in JSON in general, any types that require the "factory type" feature (returning an instance of a different type from GetRealObject(StreamingContext) than the type that implements the interface) are not supported.

DateTime 连网格式DateTime Wire Format

DateTime 值显示为“/Date(700000+0500)/”形式的 JSON 字符串,其中第一个数字(在提供的示例中为 700000)是 GMT 时区中自 1970 年 1 月 1 日午夜以来按正常时间(非夏令时)经过的毫秒数。DateTime values appear as JSON strings in the form of "/Date(700000+0500)/", where the first number (700000 in the example provided) is the number of milliseconds in the GMT time zone, regular (non-daylight savings) time since midnight, January 1, 1970. 该数字可以是负数,以表示之前的时间。The number may be negative to represent earlier times. 示例中包括“+0500”的部分可选,它指示该时间属于 Local 类型,即它在反序列化时应转换为本地时区。The part that consists of "+0500" in the example is optional and indicates that the time is of the Local kind - that is, should be converted to the local time zone on deserialization. 如果没有该部分,则会将时间反序列化为 UtcIf it is absent, the time is deserialized as Utc. 实际数字(本示例中为“0500”)及其符号(+ 或 -)将被忽略。The actual number ("0500" in this example) and its sign (+ or -) are ignored.

序列化 DateTime 时,写入的 LocalUnspecified 时间将带有偏移量,而写入的 Utc 则不带偏移量。When serializing DateTime, Local and Unspecified times are written with an offset, and Utc is written without.

ASP.NET AJAX 客户端 JavaScript 代码会自动将此类字符串转换为 JavaScript DateTime 实例。The ASP.NET AJAX client JavaScript code automatically converts such strings into JavaScript DateTime instances. 如果有其他字符串采用了类似的形式,则即使它们不属于 .NET 中的 DateTime 类型,也会对它们执行转换。If there are other strings that have a similar form that are not of type DateTime in .NET, they are converted as well.

仅当对 "/" 字符进行转义时才会发生转换(也就是说,JSON 类似于 " \ /Date (700000 + 0500) \ /"),因此,出于此原因,WCF 的 json 编码器(由启用 WebHttpBinding )始终对 "/" 字符进行转义。The conversion only takes place if the "/" characters are escaped (that is, the JSON looks like "\/Date(700000+0500)\/"), and for this reason WCF's JSON encoder (enabled by the WebHttpBinding) always escapes the "/" character.

JSON 字符串中的 XMLXML in JSON Strings

XmlElementXmlElement

XmlElement 按原样执行序列化,而不进行包装。XmlElement is serialized as is, with no wrapping. 例如,包含的类型的数据成员 "x" XmlElement <abc/> 表示如下:For example, data member "x" of type XmlElement that contains <abc/> is represented as follows:

{"x":"<abc/>"}

XmlNode 数组Arrays of XmlNode

Array 类型的标准数据协定命名空间内,该类型的 XmlNode 对象被包装在一个称为 ArrayOfXmlNode 的元素中。Array objects of type XmlNode are wrapped in an element called ArrayOfXmlNode in the standard data contract namespace for the type. 如果“x”是一个数组,并包含命名空间“ns”中的属性节点“N”,且该属性节点又包含“value”和一个空元素节点“M”,则可以按以下方式表示该数组。If "x" is an array that contains attribute node "N" in namespace "ns" that contains "value" and an empty element node "M", the representation is as follows.

{"x":"<ArrayOfXmlNode xmlns=\"http://schemas.datacontract.org/2004/07/System.Xml\" a:N=\"value\" xmlns:a=\"ns\"><M/></ArrayOfXmlNode>"}

XmlNode 数组的开头(在其他元素之前)不支持空命名空间中的属性。Attributes in the empty namespace at the beginning of XmlNode arrays (before other elements) are unsupported.

包括 XElement 和 DataSet 的 IXmlSerializable 类型IXmlSerializable Types including XElement and DataSet

ISerializable 类型可分为“内容类型”、“数据集类型”和“元素类型”。ISerializable types subdivide into "content types", "DataSet types" and "element types". 有关这些类型的定义,请参阅数据协定中的 XML 和 ADO.NET 类型For definitions of these types, see XML and ADO.NET Types in Data Contracts.

“内容”和“数据集”类型类似,它们都会被序列化为上一节中所讨论的 ArrayXmlNode 对象。"Content" and "DataSet" types are serialized similar to Array objects of XmlNode discussed in the previous section. 它们的包装元素的名称和命名空间与数据协定的名称和相应类型的命名空间相对应。They are wrapped in an element whose name and namespace corresponds to the data contract name and namespace of the type in question.

“元素”类型(例如 XElement)按原样序列化,这与本主题前面讨论的 XmlElement 类似。"Element" types such as XElement are serialized as is, similar to XmlElement previously discussed in this topic.

多形性Polymorphism

保留类型信息Preserving Type Information

正如前文所述,JSON 中支持多态性,但有一些限制。As stated earlier, polymorphism is supported in JSON with some limitations. JavaScript 是一种弱类型语言,类型标识通常并不会产生问题。JavaScript is a weakly-typed language and type identity is normally not an issue. 但是,当使用 JSON 在强类型系统(.NET)与弱类型系统(JavaScript)之间进行通信时,保留类型标识将十分有用。However, when using JSON to communicate between a strongly typed system (.NET) and a weakly-typed system (JavaScript), it is useful to preserve type identity. 例如,数据协定名称为“Square”和“Circle”的类型派生自数据协定名称为“Shape”的类型。For example, types with data contract names "Square" and "Circle" derive from a type with a data contract name of "Shape". 如果将“Circle”从 .NET 发送至 JavaScript,随后又将其返回给某个需要“Shape”的 .NET 方法,则 .NET 端就需要它以知道该对象最初为“Circle”,否则任何特定于派生类型的信息(例如,“Circle”上的“radius”数据成员)都可能丢失。If "Circle" is sent from .NET to JavaScript and is later returned to a .NET method that expects "Shape", it is useful for the .NET side to know that the object in question was originally a "Circle" - otherwise any information specific to the derived type (for example, "radius" data member on "Circle") may be lost.

若要保留类型标识,可以在将复杂类型序列化为 JSON 时添加“类型提示”。这样,反序列化程序在识别该提示后,便可以执行相应的操作。To preserve type identity, when serializing complex types to JSON a "type hint" can be added, and the deserializer recognizes the hint and acts appropriately. "类型提示" 是键名称为 "type" 的 JSON 键/值对 _ _ (后跟单词 "type" 的两个下划线)。The "type hint" is a JSON key/value pair with the key name of "__type" (two underscores followed by the word "type"). 该值是一个 JSON 字符串,其形式为“数据协定名称:数据协定命名空间”(第一个冒号前的所有内容都是名称)。The value is a JSON string of the form "DataContractName:DataContractNamespace" (anything up to the first colon is the name). 在前面的示例中,“Circle”可以按以下方式进行序列化。Using the earlier example, "Circle" can be serialized as follows.

{"__type":"Circle:http://example.com/myNamespace","x":50,"y":70,"radius":10}

类型提示与 xsi:type 属性非常相似,此属性由 XML 架构实例标准定义,供序列化/反序列化 XML 时使用。The type hint is very similar to the xsi:type attribute defined by the XML Schema Instance standard and used when serializing/deserializing XML.

_ _ 由于与类型提示的潜在冲突,禁止了名为 "type" 的数据成员。Data members called "__type" are forbidden due to potential conflict with the type hint.

减小类型提示的大小Reducing the Size of Type Hints

为了减小 JSON 消息的大小,默认的数据协定命名空间前缀( http://schemas.datacontract.org/2004/07/ )将替换为 "#" 字符。To reduce the size of JSON messages, the default data contract namespace prefix (http://schemas.datacontract.org/2004/07/) is replaced with the "#" character. (若要使此替换成为可逆的,请使用转义规则:如果命名空间以 "#" 或 " \ " 个字符开头,则使用额外的 " \ " 字符追加它们。(To make this replacement reversible, an escaping rule is used: if the namespace starts with the "#" or "\" characters, they are appended with an extra "\" character). 因此,如果 "Circle" 是 .NET 命名空间 "MyApp" 中的类型,则其默认数据协定命名空间为 http://schemas.datacontract.org/2004/07/MyAppThus, if "Circle" is a type in the .NET namespace "MyApp.Shapes", its default data contract namespace is http://schemas.datacontract.org/2004/07/MyApp. 下面是 Shapes 及其 JSON 表示形式。Shapes and the JSON representation is as follows.

{"__type":"Circle:#MyApp.Shapes","x":50,"y":70,"radius":10}

在反序列化时,会了解截断的(#MyApp 形状)和完整( http://schemas.datacontract.org/2004/07/MyApp.Shapes )名称。Both the truncated (#MyApp.Shapes) and the full (http://schemas.datacontract.org/2004/07/MyApp.Shapes) names is understood on deserialization.

JSON 对象中的类型提示位置Type Hint Position in JSON Objects

请注意,类型提示必须出现在 JSON 表示形式的开头。Note that the type hint must appear first in the JSON representation. 这是 JSON 处理中唯一一种重视键/值对顺序的情况。This is the only case where order of key/value pairs is important in JSON processing. 例如,下面不是指定类型提示的有效方式。For example, the following is not a valid way to specify the type hint.

{"x":50,"y":70,"radius":10,"__type":"Circle:#MyApp.Shapes"}

DataContractJsonSerializerWCF 和 ASP.NET AJAX 客户端页使用的都始终首先发出类型提示。Both the DataContractJsonSerializer used by WCF and ASP.NET AJAX client pages always emit the type hint first.

类型提示仅适用于复杂类型Type Hints Apply Only to Complex Types

对于非复杂类型,无法发出类型提示。There is no way to emit a type hint for non-complex types. 例如,如果操作的返回类型为 Object,但却返回了 Circle,则 JSON 表示形式可能像前面显示的那样保留了类型信息。For example, if an operation has an Object return type but returns a Circle, the JSON representation can be as shown earlier and the type information is preserved. 但是,如果返回了 URI,则 JSON 表示形式将是一个字符串,而该字符串原来用于表示 URI 的事实将丢失。However, if Uri is returned, the JSON representation is a string and the fact that the string used to represent a Uri is lost. 这不仅适用于基元类型,也适用于集合和数组。This applies not only to primitive types but also to collections and arrays.

发出类型提示的时机When Are Type Hints Emitted

类型提示可能会显著增大消息的大小(缓解此问题的一种方式是尽量使用较短的数据协定命名空间)。Type hints may increase message size significantly (one way to mitigate this is to use shorter data contract namespaces if possible). 因此,在确定是否发出类型提示时,应循序下列规则:Therefore, the following rules govern whether type hints are emitted:

  • 使用 ASP.NET AJAX 时,始终都应尽可能多地发出类型提示,即使不存在基分配/派生分配(例如,将 Circle 分配给 Circle)也不例外。When using ASP.NET AJAX, type hints are always emitted whenever possible, even if there is no base/derived assignment - for example, even if a Circle is assigned to a Circle. (需要完全启用从弱类型化 JSON 环境调用到强类型化的 .NET 环境中的过程,而不会造成意外的信息丢失。)(This is required to fully enable the process of calling from the weakly-typed JSON environment into the strongly typed .NET environment with no surprising loss of information.)

  • 如果在未与 ASP.NET 集成的情况下使用 AJAX 服务,则只有当存在基分配/派生分配时才应发出类型提示,即在将 Circle 分配给 Shape 或 Object 而不是分配给 Circle 时发出。When using AJAX services with no ASP.NET integration, type hints are only emitted when there is a base/derived assignment - that is, emitted when Circle is assigned to Shape or Object but not when assigned to Circle. 这不仅满足了正确实现 JavaScript 客户端所需的信息,而且在最大程度上减少了这些信息,从而提高了性能。但是,如果客户端的设计有误,则无法防止类型信息丢失。This provides the minimum information required to correctly implement a JavaScript client, thus improving performance, but does not protect against type information loss in incorrectly-designed clients. 如果要避免处理此客户端问题,请同时避免服务器上的基分配/派生分配。Avoid base/derived assignments altogether on the server if you want to avoid dealing with this issue on the client.

  • 使用 DataContractSerializer 类型时,alwaysEmitTypeInformation 构造函数参数允许您在前面两种模式之间进行选择,其默认值为“false”(仅在需要时才发出类型提示)。When using the DataContractSerializer type, the alwaysEmitTypeInformation constructor parameter allows you to choose between the preceding two modes, with the default being "false" (only emit type hints when required).

重复的数据成员名称Duplicate Data Member Names

派生类型信息和基类型信息共同存在于同一个 JSON 对象中,且可以按任意顺序出现。Derived type information is present in the same JSON object together with base type information, and can occur in any order. 例如, Shape 可以如下所示。For example, Shape may be represented as follows.

{"__type":"Shape:#MyApp.Shapes","x":50,"y":70}

而 Circle 则可以表示为以下形式。Whereas Circle may be represented as follows.

{"__type":"Circle:#MyApp.Shapes","x":50, "radius":10,"y":70}

如果基 Shape 类型还包含名为 "" 的数据成员 radius ,则这会导致两个序列化(因为 JSON 对象不能有重复的键名)和反序列化(因为它不清楚 "radius" 是否引用 Shape.radiusCircle.radius )。If the base Shape type also contained a data member called "radius", this leads to a collision on both serialization (because JSON objects cannot have repeating key names) and deserialization (because it is unclear whether "radius" refers to Shape.radius or Circle.radius). 因此,虽然一般不建议在数据协定类中使用“属性隐藏”概念(基类和派生类中的数据成员同名),但 JSON 中实际上禁止这种情况。Therefore, while the concept of "property hiding" (data members of the same name on based and derived classes) is generally not recommended in data contract classes, it is actually forbidden in the case of JSON.

多态性和 IXmlSerializable 类型Polymorphism and IXmlSerializable Types

根据常规数据协定规则,只要满足已知类型需求,就可以用多态形式将 IXmlSerializable 类型正常分配给彼此。IXmlSerializable types may be polymorphically assigned to each other as usual as long as Known Types requirements are met, according to usual data contract rules. 但是,如果用序列化 IXmlSerializable 类型代替序列化 Object,则会像 JSON 字符串那样导致类型信息丢失。However, serializing an IXmlSerializable type in place of Object results in loss of type information as the result is a JSON string.

多态性和某些接口类型Polymorphism and Certain Interface Types

在需要非 IXmlSerializable 的非集合类型(IXmlSerializable 除外)时,禁止序列化集合类型或实现 Object 的类型。It is forbidden to serialize a collection type or a type that implements IXmlSerializable where a non-collection type that is not IXmlSerializable (except for Object) is expected. 例如,一个名为的自定义接口 IMyInterface 和一个 MyType 实现 IEnumerable<T> 类型和的 int 类型 IMyInterfaceFor example, a custom interface called IMyInterface and a type MyType that implement both IEnumerable<T> of type int and IMyInterface. 禁止 MyType 从返回类型为的操作返回 IMyInterfaceIt is forbidden to return MyType from an operation whose return type is IMyInterface. 这是因为 MyType 必须序列化为 JSON 数组并需要类型提示,并在不能将类型提示添加到数组中之前所述,而不能包含复杂类型。This is because MyType must be serialized as a JSON array and requires a type hint, and as stated before you cannot include a type hint with arrays, only with complex types.

已知类型和配置Known Types and Configuration

DataContractSerializer 使用的所有已知类型机制同样受 DataContractJsonSerializer 支持。All of the Known Type mechanisms used by the DataContractSerializer are also supported in the same way by the DataContractJsonSerializer. 这两个序列化程序读取相同的配置元素, <dataContractSerializer> <system.runtime.serialization> 以发现通过配置文件添加的已知类型。Both serializers read the same configuration element, <dataContractSerializer> in <system.runtime.serialization>, to discover known types added through a configuration file.

分配给对象的集合Collections Assigned to Object

序列化分配给对象的集合时,会将它们视为实现 IEnumerable<T> 的集合:一个 JSON 数组,其中属于复杂类型的每一项都具有类型提示。Collections assigned to Object are serialized as if they are collections that implement IEnumerable<T>: a JSON array with each entry that has a type hint if it is a complex type. 例如, List<T> 分配到的类型的如下所 Shape Object 示。For example, a List<T> of type Shape assigned to Object looks like the following.

[{"__type":"Shape:#MyApp.Shapes","x":50,"y":70},
{"__type":"Shape:#MyApp.Shapes","x":58,"y":73},
{"__type":"Shape:#MyApp.Shapes","x":41,"y":32}]

当反序列化回 Object 时:When deserialized back into Object:

  • Shape必须在已知类型列表中。Shape must be in the Known Types list. List<T> Shape 已知类型中的类型不起作用。Having List<T> of type Shape in known types has no effect. 请注意,在 Shape 这种情况下,在序列化时无需添加到已知类型-这是自动完成的。Note that you do not have to add Shape to known types on serialization in this case - this is done automatically.

  • 集合将反序列化为 Array Object 包含实例的类型的 ShapeThe collection is deserialized as an Array of type Object that contains Shape instances.

分配给基集合的派生集合Derived Collections Assigned to Base Collections

将派生集合分配给基集合时,通常会将该集合作为基类型的集合进行序列化。When a derived collection is assigned to a base collection, the collection is usually serialized as if it was a collection of the base type. 但是,如果派生集合的项类型不能分配给基集合的项类型,则会引发异常。However, if the item type of the derived collection cannot be assigned to the item type of the base collection, an exception is thrown.

类型提示和字典Type Hints and Dictionaries

将字典分配给 Object 时,字典中的每个键和值项都将被视为已分配给 Object 并会获得类型提示。When a dictionary is assigned to an Object, each Key and Value entry in the dictionary is treated as if it was assigned to Object and gets a type hint.

序列化字典类型时,包含“Key”和“Value”成员的 JSON 对象不会受 alwaysEmitTypeInformation 设置的影响,并只有在前面的集合规则需要时才会包含类型提示。When serializing dictionary types, the JSON object that contains the "Key" and "Value" members is unaffected by the alwaysEmitTypeInformation setting and only contains a type hint when the preceding collection rules require it.

有效的 JSON 键名Valid JSON Key Names

序列化程序 XML 编码的键名不是有效的 XML 名称。The serializer XML-encodes key names that are not valid XML names. 例如,名称为 "123" 的数据成员将具有编码名称(如 " _ x0031 _ _ x0032 _ _ x0033 _ "),因为 "123" 是无效的 XML 元素名称(以数字开头)。For example, a data member with the name of "123" would have an encoded name such as "_x0031__x0032__x0033_" because "123" is an invalid XML element name (starts with a digit). 在 XML 名称中,如果某些国际字符集无效,也会出现类似的情况。A similar situation may arise with some international character sets not valid in XML names. 有关 XML 对 JSON 处理的影响的说明,请参阅json 和 XML 之间的映射For an explanation of this effect of XML on JSON processing, see Mapping Between JSON and XML.

请参阅See also