Skip to content

Latest commit

 

History

History
233 lines (141 loc) · 12.3 KB

json-and-xml-serialization.md

File metadata and controls

233 lines (141 loc) · 12.3 KB
uid title author description ms.author ms.date ms.assetid msc.legacyurl msc.type
web-api/overview/formats-and-model-binding/json-and-xml-serialization
JSON and XML Serialization in ASP.NET Web API - ASP.NET 4.x
rick-anderson
Describes the JSON and XML formatters in ASP.NET Web API for ASP.NET 4.x.
riande
05/30/2012
1cd7525d-de5e-4ab6-94f0-51480d3255d1
/web-api/overview/formats-and-model-binding/json-and-xml-serialization
authoredcontent

JSON and XML Serialization in ASP.NET Web API

This article describes the JSON and XML formatters in ASP.NET Web API.

In ASP.NET Web API, a media-type formatter is an object that can:

  • Read CLR objects from an HTTP message body
  • Write CLR objects into an HTTP message body

Web API provides media-type formatters for both JSON and XML. The framework inserts these formatters into the pipeline by default. Clients can request either JSON or XML in the Accept header of the HTTP request.

Contents

JSON Media-Type Formatter

JSON formatting is provided by the JsonMediaTypeFormatter class. By default, JsonMediaTypeFormatter uses the Json.NET library to perform serialization. Json.NET is a third-party open source project.

If you prefer, you can configure the JsonMediaTypeFormatter class to use the DataContractJsonSerializer instead of Json.NET. To do so, set the UseDataContractJsonSerializer property to true:

[!code-csharpMain]

JSON Serialization

This section describes some specific behaviors of the JSON formatter, using the default Json.NET serializer. This is not meant to be comprehensive documentation of the Json.NET library; for more information, see the Json.NET Documentation.

What Gets Serialized?

By default, all public properties and fields are included in the serialized JSON. To omit a property or field, decorate it with the JsonIgnore attribute.

[!code-csharpMain]

If you prefer an "opt-in" approach, decorate the class with the DataContract attribute. If this attribute is present, members are ignored unless they have the DataMember. You can also use DataMember to serialize private members.

[!code-csharpMain]

Read-Only Properties

Read-only properties are serialized by default.

Dates

By default, Json.NET writes dates in ISO 8601 format. Dates in UTC (Coordinated Universal Time) are written with a "Z" suffix. Dates in local time include a time-zone offset. For example:

[!code-consoleMain]

By default, Json.NET preserves the time zone. You can override this by setting the DateTimeZoneHandling property:

[!code-csharpMain]

If you prefer to use Microsoft JSON date format ("\/Date(ticks)\/") instead of ISO 8601, set the DateFormatHandling property on the serializer settings:

[!code-csharpMain]

Indenting

To write indented JSON, set the Formatting setting to Formatting.Indented:

[!code-csharpMain]

Camel Casing

To write JSON property names with camel casing, without changing your data model, set the CamelCasePropertyNamesContractResolver on the serializer:

[!code-csharpMain]

Anonymous and Weakly-Typed Objects

An action method can return an anonymous object and serialize it to JSON. For example:

[!code-csharpMain]

The response message body will contain the following JSON:

[!code-jsonMain]

If your web API receives loosely structured JSON objects from clients, you can deserialize the request body to a Newtonsoft.Json.Linq.JObject type.

[!code-csharpMain]

However, it is usually better to use strongly typed data objects. Then you don't need to parse the data yourself, and you get the benefits of model validation.

The XML serializer does not support anonymous types or JObject instances. If you use these features for your JSON data, you should remove the XML formatter from the pipeline, as described later in this article.

XML Media-Type Formatter

XML formatting is provided by the XmlMediaTypeFormatter class. By default, XmlMediaTypeFormatter uses the DataContractSerializer class to perform serialization.

If you prefer, you can configure the XmlMediaTypeFormatter to use the XmlSerializer instead of the DataContractSerializer. To do so, set the UseXmlSerializer property to true:

[!code-csharpMain]

The XmlSerializer class supports a narrower set of types than DataContractSerializer, but gives more control over the resulting XML. Consider using XmlSerializer if you need to match an existing XML schema.

XML Serialization

This section describes some specific behaviors of the XML formatter, using the default DataContractSerializer.

By default, the DataContractSerializer behaves as follows:

  • All public read/write properties and fields are serialized. To omit a property or field, decorate it with the IgnoreDataMember attribute.
  • Private and protected members are not serialized.
  • Read-only properties are not serialized. (However, the contents of a read-only collection property are serialized.)
  • Class and member names are written in the XML exactly as they appear in the class declaration.
  • A default XML namespace is used.

If you need more control over the serialization, you can decorate the class with the DataContract attribute. When this attribute is present, the class is serialized as follows:

  • "Opt in" approach: Properties and fields are not serialized by default. To serialize a property or field, decorate it with the DataMember attribute.
  • To serialize a private or protected member, decorate it with the DataMember attribute.
  • Read-only properties are not serialized.
  • To change how the class name appears in the XML, set the Name parameter in the DataContract attribute.
  • To change how a member name appears in the XML, set the Name parameter in the DataMember attribute.
  • To change the XML namespace, set the Namespace parameter in the DataContract class.

Read-Only Properties

Read-only properties are not serialized. If a read-only property has a backing private field, you can mark the private field with the DataMember attribute. This approach requires the DataContract attribute on the class.

[!code-csharpMain]

Dates

Dates are written in ISO 8601 format. For example, "2012-05-23T20:21:37.9116538Z".

Indenting

To write indented XML, set the Indent property to true:

[!code-csharpMain]

Setting Per-Type XML Serializers

You can set different XML serializers for different CLR types. For example, you might have a particular data object that requires XmlSerializer for backward compatibility. You can use XmlSerializer for this object and continue to use DataContractSerializer for other types.

To set an XML serializer for a particular type, call SetSerializer.

[!code-csharpMain]

You can specify an XmlSerializer or any object that derives from XmlObjectSerializer.

Removing the JSON or XML Formatter

You can remove the JSON formatter or the XML formatter from the list of formatters, if you do not want to use them. The main reasons to do this are:

  • To restrict your web API responses to a particular media type. For example, you might decide to support only JSON responses, and remove the XML formatter.
  • To replace the default formatter with a custom formatter. For example, you could replace the JSON formatter with your own custom implementation of a JSON formatter.

The following code shows how to remove the default formatters. Call this from your Application_Start method, defined in Global.asax.

[!code-csharpMain]

Handling Circular Object References

By default, the JSON and XML formatters write all objects as values. If two properties refer to the same object, or if the same object appears twice in a collection, the formatter will serialize the object twice. This is a particular problem if your object graph contains cycles, because the serializer will throw an exception when it detects a loop in the graph.

Consider the following object models and controller.

[!code-csharpMain]

Invoking this action will cause the formatter to throw an exception, which translates to a status code 500 (Internal Server Error) response to the client.

To preserve object references in JSON, add the following code to Application_Start method in the Global.asax file:

[!code-csharpMain]

Now the controller action will return JSON that looks like this:

[!code-jsonMain]

Notice that the serializer adds an "$id" property to both objects. Also, it detects that the Employee.Department property creates a loop, so it replaces the value with an object reference: {"$ref":"1"}.

Note

Object references are not standard in JSON. Before using this feature, consider whether your clients will be able to parse the results. It might be better simply to remove cycles from the graph. For example, the link from Employee back to Department is not really needed in this example.

To preserve object references in XML, you have two options. The simpler option is to add [DataContract(IsReference=true)] to your model class. The IsReference parameter enables object references. Remember that DataContract makes serialization opt-in, so you will also need to add DataMember attributes to the properties:

[!code-csharpMain]

Now the formatter will produce XML similar to following:

[!code-xmlMain]

If you want to avoid attributes on your model class, there is another option: Create a new type-specific DataContractSerializer instance and set preserveObjectReferences to true in the constructor. Then set this instance as a per-type serializer on the XML media-type formatter. The following code show how to do this:

[!code-csharpMain]

Testing Object Serialization

As you design your web API, it is useful to test how your data objects will be serialized. You can do this without creating a controller or invoking a controller action.

[!code-csharpMain]