System.Text.Json’s serialization APIs aren’t all that different from Json.NET, but there are a few differences that make it more practical than its predecessor. This post explores how those options can help you be more effective when working with JSON.
This is the third post in a series on System.Text.Json. The other posts are:
- Part 1: Why System.Text.Json exists, major differences with Newtonsoft, and how to find help with the new library.
- Part 2: Reading JSON documents.
- Part 3 [this post]: Writing JSON documents.
- Part 4 [coming soon]: Model Binding in ASP.NET Core.
- Part 5 [coming soon]: Considerations for using System.Text.Json in a production-grade project.
There are three different ways to serialize data with System.Text.Json. The one you use depends on the type of data that you’re working with.
JsonSerializerclass is how you serialize POCOs to formatted JSON. It’s very similar to Newtonsoft’s
JsonConvert, with different defaults and a few specialized implementations.
JsonDocument‘s API is primarily for reading documents for which you don’t know the structure, but you can still write all or parts of that JSON document back out, as need be.
Utf8JsonWriteris the class pulling all the strings behind the scenes. You can also make use of its API directly to control every aspect of how to write a JSON document.
Let’s look at each of these approaches in more detail.
JsonSerializer has three methods for serializing an object to JSON, giving you the flexibility to use the one that best fits your scenario.
The most commonly used method,
Serialize, does what you’d expect. It takes a POCO and creates a string representation of that object in JSON. For example, I most frequently use
Serialize to create a JSON body for HTTP requests:
var content = JsonSerializer.Serialize<FlightPlan>(flightPlan); await httpClient.PostAsync(requestUri, new StringContent(content, Encoding.UTF8, ApplicationJsonContentType));
In Json.NET, I would have used
SerializeObject to create JSON meant for a file on disk or messaging platform like Azure Service Bus. Luckily, there is a more efficient way to do that with System.Text.Json. The
SerializeAsync method exists to write JSON asynchronously to a stream. It avoids a string allocation and writes the serialized object to the stream without blocking. You should use it anytime you’re working with something that supports a stream:
using Stream writer = new FileStream("flightplan.json", FileMode.OpenOrCreate); await JsonSerializer.SerializeAsync(writer, flightPlan);
SerializeToUtf8Bytes creates a byte array that represents the JSON string. You won’t need this method too often, but it can come in handy for specialized handling. As an example, I’ve written the JSON out as a base64 string:
var result = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes<FlightPlan>(flightPlan); var base64Result = Convert.ToBase64String(result);
You should use JsonSerializer ‘s Serialize methods when
- You have a POCO that you need to transform to JSON.
- You need to write the JSON to a string, stream, or raw bytes for further manipulation.
JsonDocument (via Utf8JsonWriter)
JsonDocument API is useful for reading JSON documents that are either in an unknown format or are too big to deserialize into a POCO. It might seem like an API that’s meant for reading JSON wouldn’t need to write JSON, but there are a few scenarios where it proves useful.
JsonDocument is composed of any number of
JsonElements, starting with the root element. Every
JsonElement has a
GetRawText return the original JSON string representation of the
JsonElement‘s value. It can be used for simple cases where you need part of a JSON object in a string:
var waypointsJson = flightPlans.RootElement.GetProperty("Revised").GetProperty("Waypoints").GetRawText(); // Do something with waypointsJson
The more useful method is
WriteTo, which takes a
Utf8JsonWriter as a parameter. It opens up a few options, most notably to create a new JSON from existing elements of the
JsonDocument. The example below is a bit contrived, but shows the power of the
WriteTo method to combine element into a new JSON:
// Read a large JSON string into a JsonDocument var flightPlans = JsonDocument.Parse(JsonFlightPlans()); // Prepare the destination for the new JSON document we're going to create using Stream waypointsStreamWriter = new FileStream("allwaypoints.json", FileMode.OpenOrCreate); var utf8MemoryWriter = new Utf8JsonWriter(waypointsStreamWriter); // Create the new object utf8MemoryWriter.WriteStartObject(); // Add the initial waypoints of the flight plan by accessing the property and writing it to the writer utf8MemoryWriter.WritePropertyName("InitialWaypoints"); flightPlans.RootElement.GetProperty("Initial").GetProperty("Waypoints").WriteTo(utf8MemoryWriter); // Add the revised waypoints in the same way as the initial waypoints utf8MemoryWriter.WritePropertyName("RevisedWaypoints"); flightPlans.RootElement.GetProperty("Revised").GetProperty("Waypoints").WriteTo(utf8MemoryWriter); utf8MemoryWriter.WriteEndObject(); utf8MemoryWriter.Flush();
Utf8JsonWriter APIs can be a powerful tool when combined to create JSON. It’s not something you’ll need every day, but it’s nice to know the basic building blocks are there when you need them.
You should use JsonDocument and JsonElement serialization methods when
- You’re already working with a
- You want to build a JSON document based on the content of an existing JSON document.
There is a
Utf8JsonWriter at work under the covers of both
JsonDocument‘s serialization methods. You can be more productive working with the higher level abstractions of
JsonDocument, while still taking advantage of the performance of
Utf8JsonWriter also opens up the ability to handle your own custom serialization needs, such as creating a standardized JSON format for use within your applications. The options are endless, and the best part is that you don’t need to build everything from scratch, since you can leave the writing of valid JSON to
You should use Utf8JsonWriter when
- You want to create JSON from scratch.
- You want to build a custom JSON serializer but not worry about every single edge case of writing valid JSON.
There are a few different ways to serialize JSON data with System.Text.Json. The method you chose depends on what you have, and what you’re doing with the serialized data. In most cases,
JsonSerializer is what you’re looking for, but there are times where you’ll need to use
Utf8JsonWriter to handle more funky scenarios.
With the basics of serialization and deserialization covered, it’s now time to learn how ASP.NET Core interacts with System.Text.Json. That’ll be the topic of the next post, arriving in early December.