295 lines
15 KiB
XML
295 lines
15 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<topic id="SerializationGuide" revisionNumber="1">
|
|
<developerConceptualDocument xmlns="http://ddue.schemas.microsoft.com/authoring/2003/5" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
<!--
|
|
<summary>
|
|
<para>Optional summary abstract</para>
|
|
</summary>
|
|
-->
|
|
<introduction>
|
|
<para>The Json.NET serializer can serialize a wide variety of .NET objects. This guide looks at how it works, first at a high level and then in more detail.</para>
|
|
<autoOutline lead="none" excludeRelatedTopics="true" />
|
|
</introduction>
|
|
<!-- Add one or more top-level section elements. These are collapsible.
|
|
If using <autoOutline />, add an address attribute to identify it
|
|
and specify a title so that it can be jumped to with a hyperlink. -->
|
|
<section address="Summary">
|
|
<title>Summary</title>
|
|
<content>
|
|
<!-- Uncomment this to create a sub-section outline
|
|
<autoOutline /> -->
|
|
<para>At a high level, the Json.NET serializer will convert primitive .NET values into primitive JSON values,
|
|
will convert .NET arrays and collections to JSON arrays, and will convert everything else to JSON objects.</para>
|
|
<para>Json.NET will throw an error if it encounters incorrect JSON when deserializing a value. For example, if
|
|
the serializer encounters a JSON property with an array of values and the type of matching .NET property is not
|
|
a collection, then an error will be thrown, and vice-versa.</para>
|
|
</content>
|
|
</section>
|
|
<section address="ComplexTypes">
|
|
<title>Complex Types</title>
|
|
<content>
|
|
<table>
|
|
<tableHeader>
|
|
<row>
|
|
<entry><para>.NET</para></entry>
|
|
<entry><para>JSON</para></entry>
|
|
</row>
|
|
</tableHeader>
|
|
<row>
|
|
<entry><para><legacyBold>IList, IEnumerable, IList<T>, Array</legacyBold></para></entry>
|
|
<entry><para>Array (properties on the collection will not be serialized)</para></entry>
|
|
</row>
|
|
<row>
|
|
<entry><para><legacyBold>IDictionary, IDictionary<TKey, TValue></legacyBold></para></entry>
|
|
<entry><para>Object (dictionary name/values only, properties on the dictionary will not be serialized)</para></entry>
|
|
</row>
|
|
<row>
|
|
<entry><para><legacyBold>Object (more detail below)</legacyBold></para></entry>
|
|
<entry><para>Object</para></entry>
|
|
</row>
|
|
</table>
|
|
</content>
|
|
</section>
|
|
<section address="PrimitiveTypes">
|
|
<title>Primitive Types</title>
|
|
<content>
|
|
<table>
|
|
<tableHeader>
|
|
<row>
|
|
<entry><para>.NET</para></entry>
|
|
<entry><para>JSON</para></entry>
|
|
</row>
|
|
</tableHeader>
|
|
<row>
|
|
<entry><para><legacyBold>String</legacyBold></para></entry>
|
|
<entry><para>String</para></entry>
|
|
</row>
|
|
<row>
|
|
<entry><para><legacyBold>Byte</legacyBold></para>
|
|
<para><legacyBold>SByte</legacyBold></para>
|
|
<para><legacyBold>UInt16</legacyBold></para>
|
|
<para><legacyBold>Int16</legacyBold></para>
|
|
<para><legacyBold>UInt32</legacyBold></para>
|
|
<para><legacyBold>Int32</legacyBold></para>
|
|
<para><legacyBold>UInt64</legacyBold></para>
|
|
<para><legacyBold>Int64</legacyBold></para></entry>
|
|
<entry><para>Integer</para></entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
<para><legacyBold>Float</legacyBold></para>
|
|
<para><legacyBold>Double</legacyBold></para>
|
|
<para><legacyBold>Decimal</legacyBold></para>
|
|
</entry>
|
|
<entry><para>Float</para></entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
<para><legacyBold>Enum</legacyBold></para>
|
|
</entry>
|
|
<entry><para>Integer (can be the enum value name with <codeEntityReference>T:Newtonsoft.Json.Converters.StringEnumConverter</codeEntityReference>)</para></entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
<para><legacyBold>DateTime</legacyBold></para>
|
|
</entry>
|
|
<entry><para>String (<link xlink:href="DatesInJSON" />)</para></entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
<para><legacyBold>Byte[]</legacyBold></para>
|
|
</entry>
|
|
<entry><para>String (base 64 encoded)</para></entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
<para><legacyBold>Type</legacyBold></para>
|
|
</entry>
|
|
<entry><para>String (type name)</para></entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
<para><legacyBold>Guid</legacyBold></para>
|
|
</entry>
|
|
<entry><para>String</para></entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
<para><legacyBold><codeEntityReference>T:System.ComponentModel.TypeConverter</codeEntityReference> (convertible to String)</legacyBold></para>
|
|
</entry>
|
|
<entry><para>String</para></entry>
|
|
</row>
|
|
</table>
|
|
</content>
|
|
</section>
|
|
|
|
<section address="Breakdown">
|
|
<title>Breakdown of Type Serialization</title>
|
|
<content>
|
|
<autoOutline />
|
|
</content>
|
|
<sections>
|
|
<section address="Objects">
|
|
<title>Objects</title>
|
|
<content>
|
|
<!-- Uncomment this to create a sub-section outline
|
|
<autoOutline /> -->
|
|
<para>.NET types that don't fall into any other category listed below
|
|
(i.e. aren't lists, dictionaries, dynamic, implement ISerializable, etc.)
|
|
are serialized as JSON objects. You can also force a type to be serialized as a JSON object by placing the
|
|
JsonObjectAttribute on the type.</para>
|
|
<para>By default a type's properties are serialized in opt-out mode. What that means is that all public fields and properties with
|
|
getters are automatically serialized to JSON, and fields and properties that shouldn't be serialized are opted-out by placing
|
|
JsonIgnoreAttribute on them. To serialize private members, the JsonPropertyAttribute can be placed on private fields and
|
|
properties.</para>
|
|
<para>Types can also be serialized using opt-in mode. Only properties and fields that have a JsonPropertyAttribute
|
|
or DataMemberAttribute on them will be serialized. Opt-in mode for an object is specified by placing the JsonObjectAttribute
|
|
or DataContractAttribute on the type.</para>
|
|
<para>Finally, types can be serialized using a fields mode. All fields, both public and private, are serialized
|
|
and properties are ignored. This can be specified by setting MemberSerialization.Fields on a type with the JsonObjectAttribute
|
|
or by using the .NET <codeEntityReference>T:System.SerializableAttribute</codeEntityReference>
|
|
and setting IgnoreSerializableAttribute on DefaultContractResolver to false.</para>
|
|
</content>
|
|
</section>
|
|
|
|
<section address="Lists">
|
|
<title>IEnumerable, Lists, and Arrays</title>
|
|
<content>
|
|
<!-- Uncomment this to create a sub-section outline
|
|
<autoOutline /> -->
|
|
<para> .NET lists (types that inherit from IEnumerable) and .NET arrays are converted to JSON arrays. Because JSON
|
|
arrays only support a range of values and not properties, any additional properties and fields declared on .NET
|
|
collections are not serialized. In situations where a type implements IEnumerable but a JSON array is not wanted, then
|
|
the JsonObjectAttribute can be placed on the type to force it to be serialized as a JSON object instead.</para>
|
|
<para>JsonArrayAttribute has options on it to customize the JsonConverter, type name handling, and reference handling
|
|
that are applied to collection items.</para>
|
|
<para>Note that if TypeNameHandling or PreserveReferencesHandling has been enabled for JSON arrays on the serializer,
|
|
then JSON arrays are wrapped in a containing object. The object will have the type name/reference properties and a
|
|
$values property, which will have the collection data.</para>
|
|
<para>When deserializing, if a member is typed as the interface IList<T>, then it will be deserialized as a
|
|
List<T>.</para>
|
|
<para>You can read more about serializing collections here: <link xlink:href="SerializingCollections" /></para>
|
|
</content>
|
|
</section>
|
|
|
|
<section address="Dictionarys">
|
|
<title>Dictionaries and Hashtables</title>
|
|
<content>
|
|
<!-- Uncomment this to create a sub-section outline
|
|
<autoOutline /> -->
|
|
<para>.NET dictionaries (types that inherit from IDictionary) are converted to JSON objects. Note that only the
|
|
dictionary name/values will be written to the JSON object when serializing, and properties on the JSON object will
|
|
be added to the dictionary's name/values when deserializing. Additional members on the .NET dictionary are ignored
|
|
during serialization.</para>
|
|
<para>When serializing a dictionary, the keys of the dictionary are converted to strings and used as the
|
|
JSON object property names. The string written for a key can be customized by either overriding
|
|
<codeEntityReference>M:System.Object.ToString</codeEntityReference> for the key type or by implementing a
|
|
<codeEntityReference>T:System.ComponentModel.TypeConverter</codeEntityReference>. A TypeConverter will also
|
|
support converting a custom string back again when deserializing a dictionary.</para>
|
|
<para>JsonDictionaryAttribute has options on it to customize the JsonConverter, type name handling, and reference
|
|
handling that are applied to collection items.</para>
|
|
<para>When deserializing, if a member is typed as the interface IDictionary<TKey, TValue> then it will be
|
|
deserialized as a Dictionary<TKey, TValue>.</para>
|
|
<para>You can read more about serializing collections here: <link xlink:href="SerializingCollections" /></para>
|
|
</content>
|
|
</section>
|
|
|
|
<section address="Untyped_Objects">
|
|
<title>Untyped Objects</title>
|
|
<content>
|
|
<!-- Uncomment this to create a sub-section outline
|
|
<autoOutline /> -->
|
|
<para>.NET properties on a class that don't specify a type (i.e. they are just <codeInline>object</codeInline>) are serialized as usual. When
|
|
untyped properties are deserialized, the serializer has no way of knowing what type to create (unless type name handling
|
|
is enabled and the JSON contains the type names).</para>
|
|
<para>For these untyped properties, the Json.NET serializer will read the JSON into LINQ to JSON objects and set them
|
|
to the property. JObject will be created for JSON objects; JArray will be created for JSON arrays, and JValue will be
|
|
created for primitive JSON values.</para>
|
|
</content>
|
|
</section>
|
|
|
|
<section address="Dynamic">
|
|
<title>Dynamic</title>
|
|
<content>
|
|
<!-- Uncomment this to create a sub-section outline
|
|
<autoOutline /> -->
|
|
<para>There are two different usages of <codeInline>dynamic</codeInline> (introduced in .NET 4) in .NET. The first are .NET properties with a
|
|
type of dynamic. Dynamic properties behave like properties declared as object: any value can be assigned to it, but
|
|
the difference being that properties and methods can be called on a dynamic property without casting. In Json.NET,
|
|
dynamic properties are serialized and deserialized exactly the same as untyped objects: because dynamic isn't an actual
|
|
type, Json.NET falls back to deserializing the JSON as LINQ to JSON objects.</para>
|
|
<para>The second usage of dynamic in .NET are by the types that implement
|
|
<codeEntityReference>T:System.Dynamic.IDynamicMetaObjectProvider</codeEntityReference>. This interface lets
|
|
the implementer create dynamic objects that intercept the property and method calls on an object and use them.
|
|
<codeEntityReference>T:System.Dynamic.ExpandoObject</codeEntityReference>
|
|
is a good example of a dynamic object.</para>
|
|
<para>Dynamic objects are serialized as JSON objects. A property is written for every member name returned by
|
|
<codeEntityReference qualifyHint="true">M:System.Dynamic.DynamicMetaObject.GetDynamicMemberNames</codeEntityReference>.
|
|
A dynamic object's normal properties aren't serialized by default but can be included by placing the
|
|
JsonPropertyAttribute on them.
|
|
</para>
|
|
<para>When deserializing dynamic objects, the serializer first attempts to set JSON property values on a normal .NET
|
|
member with the matching name. If no .NET member is found with the property name, then the serializer will call
|
|
SetMember on the dynamic object. Because there is no type information for dynamic members on a dynamic object, the
|
|
values assigned to them will be LINQ to JSON objects.</para>
|
|
</content>
|
|
</section>
|
|
|
|
<section address="ISerializable">
|
|
<title>ISerializable</title>
|
|
<content>
|
|
<!-- Uncomment this to create a sub-section outline
|
|
<autoOutline /> -->
|
|
<para>Types that implement <codeEntityReference>T:System.Runtime.Serialization.ISerializable</codeEntityReference> and
|
|
are marked with <codeEntityReference>T:System.SerializableAttribute</codeEntityReference> are serialized as JSON objects. When serializing, only the values returned from
|
|
ISerializable.GetObjectData are used; members on the type are ignored. When deserializing, the constructor with a
|
|
SerializationInfo and StreamingContext is called, passing the JSON object's values.</para>
|
|
<para>In situations where this behavior is not wanted, the JsonObjectAttribute can be placed on a .NET type that
|
|
implements ISerializable to force it to be serialized as a normal JSON object.</para>
|
|
</content>
|
|
</section>
|
|
|
|
<section address="LINQ">
|
|
<title>LINQ to JSON</title>
|
|
<content>
|
|
<!-- Uncomment this to create a sub-section outline
|
|
<autoOutline /> -->
|
|
<para>LINQ to JSON types (e.g. JObject and JArray) are automatically serialized and deserialized to their equivalent JSON
|
|
when encountered by the Json.NET serializer.</para>
|
|
</content>
|
|
</section>
|
|
|
|
<section address="JsonConverter">
|
|
<title>JsonConverter</title>
|
|
<content>
|
|
<!-- Uncomment this to create a sub-section outline
|
|
<autoOutline /> -->
|
|
<para>Serialization of values that are convertible by a <codeEntityReference>T:Newtonsoft.Json.JsonConverter</codeEntityReference>
|
|
(i.e. CanConvert returns true for its type) is
|
|
completely overridden by the JsonConverter. The test to see whether a value can be converted by the JsonSerializer takes
|
|
precedence over all other tests.</para>
|
|
<para>JsonConverters can be defined and specified in a number of places: in an attribute on a member, in an attribute
|
|
on a class, and added to the JsonSerializer's converters collection. The priority of which JsonConverter is used is the
|
|
JsonConverter defined by attribute on a member, then the JsonConverter defined by an attribute on a class, and finally
|
|
any converters passed to the JsonSerializer.</para>
|
|
|
|
<alert class="note">
|
|
<para>Because a JsonConverter creates a new value, a converter will not work with readonly properties because there is no way to assign the new
|
|
value to the property. Either change the property to have a public setter or place a JsonPropertyAttribute or DataMemberAttribute on the property.</para>
|
|
</alert>
|
|
|
|
</content>
|
|
</section>
|
|
|
|
</sections>
|
|
</section>
|
|
<relatedTopics>
|
|
<link xlink:href="SerializationSettings" />
|
|
<link xlink:href="SerializationAttributes" />
|
|
<link xlink:href="DatesInJSON" />
|
|
|
|
<codeEntityReference>T:Newtonsoft.Json.JsonSerializer</codeEntityReference>
|
|
<codeEntityReference>T:Newtonsoft.Json.JsonSerializerSettings</codeEntityReference>
|
|
</relatedTopics>
|
|
</developerConceptualDocument>
|
|
</topic> |