CodeGym /Courses /C# SELF /Configuring serialization (

Configuring serialization ( JsonSerializerOptions)

C# SELF
Level 45, Lesson 3
Available

1. Introduction

Everything is fine if your needs match the defaults. But pretty often a client (or a third-party backend) requires a strict format: everywhere camelCase, dates — ISO 8601, null skipping, custom converters, and other joys of integrators.

This is where our new friend steps in — the JsonSerializerOptions class.

If serialization were a kitchen, this class is your spices, pots and secret ingredients you can use to season serialization to taste.

How to use JsonSerializerOptions

To customize the serialization or deserialization process, we just pass a settings object to the serializer methods:

using System.Text.Json;

var options = new JsonSerializerOptions
{
    // Here will be your settings
};

string json = JsonSerializer.Serialize(myObject, options);
var obj = JsonSerializer.Deserialize<MyType>(json, options);

This pattern is everywhere: you create a JsonSerializerOptions, tweak it to taste (see below), and pass it to the serializer methods Serialize/Deserialize.

Important: The same JsonSerializerOptions instance can (and should) be reused for multiple serializations.

2. Main settings of JsonSerializerOptions

Let's look at the most popular "knobs" and "switches" of this class.

JSON formatting — WriteIndented

Do one-line JSON strings hurt your eyes? No problem — enable pretty printing with indentation!

var options = new JsonSerializerOptions
{
    WriteIndented = true // Pretty, "human" JSON
};

var person = new Person { Name = "Anna", Age = 30 };
string json = JsonSerializer.Serialize(person, options);

Console.WriteLine(json);

Output:

{
  "Name": "Anna",
  "Age": 30
}

Without WriteIndented = true you'd get boring {"Name":"Anna","Age":30}. In production people usually use "minified" JSON (smaller payload), and for debugging and logs — formatted.

Case naming — PropertyNamingPolicy

Often APIs require property names to be in camelCase (for example, firstName instead of FirstName). In .NET properties are usually named in PascalCase, and that's where PropertyNamingPolicy comes in handy:

var options = new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};

var person = new Person { Name = "Bob", Age = 25 };
string json = JsonSerializer.Serialize(person, options);
Console.WriteLine(json); // {"name":"Bob","age":25}

If you need a custom style (for example, ALL_CAPS), you can implement your own JsonNamingPolicy. Usually CamelCase is enough.

3. Ignoring properties

Skip or not skip null values — DefaultIgnoreCondition

Sometimes you want fields with empty (null) values to not appear in JSON at all. Reason — more compact JSON, or an external system doesn't like null.

For that we use the DefaultIgnoreCondition property:

using System.Text.Json.Serialization;

var options = new JsonSerializerOptions
{
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};

var person = new Person { Name = null, Age = 22 };
string json = JsonSerializer.Serialize(person, options);
Console.WriteLine(json); // {"Age":22}

If you want to ignore not only null but also default values (for example, int=0), use WhenWritingDefault:

options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault;

Include fields or not — IncludeFields and [JsonInclude]

By default only public properties with a public setter are serialized. If you want to serialize fields too, you can enable:

var options = new JsonSerializerOptions
{
    IncludeFields = true
};

Example class:

public class Item
{
    public string Name;
    public int Id { get; set; }
}

var item = new Item { Name = "Book", Id = 12 };
string json = JsonSerializer.Serialize(item, options);
// {"Name":"Book","Id":12}

To serialize private fields/properties you can use the [JsonInclude] attribute, but that's a topic for another lecture.

4. Converting values

Date formatting — Converters

By default System.Text.Json serializes dates strictly in ISO 8601 format (for example, "2023-12-27T15:30:45.123Z"), which is almost always convenient. But there are cases when the date/time format must be special.

For that you plug in custom converters. A basic example:

using System.Text.Json;
using System.Text.Json.Serialization;

public class CustomDateTimeConverter : JsonConverter<DateTime>
{
    private string _format = "yyyyMMdd";

    public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var date = reader.GetString();
        return DateTime.ParseExact(date, _format, null);
    }

    public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.ToString(_format));
    }
}

// Use the converter
var options = new JsonSerializerOptions();
options.Converters.Add(new CustomDateTimeConverter());

var dateObj = new { Date = new DateTime(2022, 1, 5) };
string json = JsonSerializer.Serialize(dateObj, options); // {"Date":"20220105"}

5. Useful nuances

Case-insensitive property matching on deserialization — PropertyNameCaseInsensitive

var options = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true
};

var json = "{\"name\":\"John\",\"age\":33}";
var person = JsonSerializer.Deserialize<Person>(json, options);
// person.Name == "John"

Control nesting and max object depth — MaxDepth

var options = new JsonSerializerOptions
{
    MaxDepth = 32 // Default is 64
};

But if your objects can be infinite in nesting — for example, a tree with parent/child references — it's better to design the model differently.

Comments in JSON — ReadCommentHandling (deserialization)

JSON doesn't officially support comments, but sometimes you meet "creative" files with // comments.

var options = new JsonSerializerOptions
{
    ReadCommentHandling = JsonCommentHandling.Skip
};

string json = "{\n  \"Name\": \"John\", // User name\n  \"Age\": 30\n}";
var person = JsonSerializer.Deserialize<Person>(json, options);

Support for special characters — Encoder

Sometimes you need to control how the serializer escapes characters (for example, to avoid turning Cyrillic into \uXXXX). You can set a custom encoder:

using System.Text.Encodings.Web;

var options = new JsonSerializerOptions
{
    Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};

Use with caution, otherwise your emojis/ideographs might suddenly "turn into" Unicode sequences!

6. Common mistakes when configuring serialization

Mistake #1: forgetting a public setter. A field or property isn't serialized because it doesn't have a public setter, or it's private.

Mistake #2: wrong null ignoring. With DefaultIgnoreCondition enabled, properties with null won't appear in JSON, even if you didn't expect that.

Mistake #3: wrong date format. The date is serialized not the way you need — plug in a custom converter (JsonConverter).

Mistake #4: expecting a fixed property order. The JSON standard doesn't guarantee field order. If an API requires strict order, you'll need to either change the model or use third-party libraries.

Mistake #5: different settings for serialization and deserialization. If you don't use the same JsonSerializerOptions for writing and reading JSON, you can get errors, e.g. with name casing or formats.

2
Task
C# SELF, level 45, lesson 3
Locked
Setting Date Format in JSON
Setting Date Format in JSON
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION