JSON serialization and deserialization (marshalling and unmarshalling) in .NET - overview
The System.Text.Json namespace provides functionality for serializing to and deserializing from JavaScript Object Notation (JSON). Serialization is the process of converting the state of an object, that is, the values of its properties, into a form that can be stored or transmitted. The serialized form doesn't include any information about an object's associated methods. Deserialization reconstructs an object from the serialized form.
The System.Text.Json
library design emphasizes high performance and low memory allocation over an extensive feature set. Built-in UTF-8 support optimizes the process of reading and writing JSON text encoded as UTF-8, which is the most prevalent encoding for data on the web and files on disk.
The library also provides classes for working with an in-memory document object model (DOM). This feature enables random access to the elements in a JSON file or string.
For Visual Basic, there are some limitations on what parts of the library you can use. For more information, see Visual Basic support.
How to get the library
The library is built-in as part of the shared framework for .NET Core 3.0 and later versions. The source generation feature is built-in as part of the shared framework for .NET 6 and later versions.
For framework versions earlier than .NET Core 3.0, install the System.Text.Json NuGet package. The package supports:
- .NET Standard 2.0 and later
- .NET Framework 4.6.2 and later
- .NET Core 2.1 and later
- .NET 5 and later
Namespaces and APIs
- The System.Text.Json namespace contains all the entry points and the main types.
- The System.Text.Json.Serialization namespace contains attributes and APIs for advanced scenarios and customization specific to serialization and deserialization.
The code examples shown in this article require using
directives for one or both of these namespaces.
Important
System.Text.Json
doesn't support the following serialization APIs that you might have used previously:
- Attributes from the System.Runtime.Serialization namespace.
- The System.SerializableAttribute attribute and the ISerializable interface. These types are used only for Binary and XML serialization.
HttpClient and HttpContent extension methods
Serializing and deserializing JSON payloads from the network are common operations. Extension methods on HttpClient and HttpContent let you do these operations in a single line of code. These extension methods use web defaults for JsonSerializerOptions.
The following example illustrates use of HttpClientJsonExtensions.GetFromJsonAsync and HttpClientJsonExtensions.PostAsJsonAsync:
using System.Net.Http.Json;
namespace HttpClientExtensionMethods
{
public class User
{
public int Id { get; set; }
public string? Name { get; set; }
public string? Username { get; set; }
public string? Email { get; set; }
}
public class Program
{
public static async Task Main()
{
using HttpClient client = new()
{
BaseAddress = new Uri("https://jsonplaceholder.typicode.com")
};
// Get the user information.
User? user = await client.GetFromJsonAsync<User>("users/1");
Console.WriteLine($"Id: {user?.Id}");
Console.WriteLine($"Name: {user?.Name}");
Console.WriteLine($"Username: {user?.Username}");
Console.WriteLine($"Email: {user?.Email}");
// Post a new user.
HttpResponseMessage response = await client.PostAsJsonAsync("users", user);
Console.WriteLine(
$"{(response.IsSuccessStatusCode ? "Success" : "Error")} - {response.StatusCode}");
}
}
}
// Produces output like the following example but with different names:
//
//Id: 1
//Name: Tyler King
//Username: Tyler
//Email: Tyler@contoso.com
//Success - Created
Imports System.Net.Http
Imports System.Net.Http.Json
Namespace HttpClientExtensionMethods
Public Class User
Public Property Id As Integer
Public Property Name As String
Public Property Username As String
Public Property Email As String
End Class
Public Class Program
Public Shared Async Function Main() As Task
Using client As New HttpClient With {
.BaseAddress = New Uri("https://jsonplaceholder.typicode.com")
}
' Get the user information.
Dim user1 As User = Await client.GetFromJsonAsync(Of User)("users/1")
Console.WriteLine($"Id: {user1.Id}")
Console.WriteLine($"Name: {user1.Name}")
Console.WriteLine($"Username: {user1.Username}")
Console.WriteLine($"Email: {user1.Email}")
' Post a new user.
Dim response As HttpResponseMessage = Await client.PostAsJsonAsync("users", user1)
Console.WriteLine(
$"{(If(response.IsSuccessStatusCode, "Success", "Error"))} - {response.StatusCode}")
End Using
End Function
End Class
End Namespace
' Produces output like the following example but with different names:
'
'Id: 1
'Name: Tyler King
'Username: Tyler
'Email: Tyler@contoso.com
'Success - Created
There are also extension methods for System.Text.Json on HttpContent.
Reflection vs. source generation
By default, System.Text.Json
gathers the metadata it needs to access properties of objects for serialization and deserialization at run time using reflection. As an alternative, System.Text.Json
can use the C# source generation feature to improve performance, reduce private memory usage, and facilitate assembly trimming, which reduces app size.
For more information, see Reflection versus source generation.
Security information
For information about security threats that were considered when designing JsonSerializer, and how they can be mitigated, see System.Text.Json
Threat Model.
Thread safety
The System.Text.Json
serializer was designed with thread safety in mind. Practically, this means that once locked, JsonSerializerOptions instances can be safely shared across multiple threads. JsonDocument provides an immutable, and in .NET 8 and later versions, thread-safe, DOM representation for JSON values.