How to exclude a property from being serialized in System.Text.Json.JsonSerializer.Serialize() using a JsonConverter

.net-core, c#, json, serialization

Solution

So I happened to stumble upon an article that demonstrates how to use the `JsonDocument` object in the new `System.Text.Json` namespace and it is the next best thing to a Fluent API. Here is how this question can be solved.

The BookConverter.Write() method:

public override void Write(Utf8JsonWriter writer, Book value, JsonSerializerOptions options)
{
    writer.WriteStartObject();

    using (JsonDocument document = JsonDocument.Parse(JsonSerializer.Serialize(value)))
    {
        foreach (var property in document.RootElement.EnumerateObject())
        {
            if (property.Name != "Author")
                property.WriteTo(writer);
        }
    }

    writer.WriteEndObject();
}

Problem

I want to be able to exclude a property when serializing using System.Text.Json.JsonSerializer. I don't want to use a `JsonIgnore` attribute everywhere I want to do this. I would like to be able to define the properties I want to exclude during serialization only, via some kind of Fluent API, which currently does not exist. The only option I was able to find is to define a `JsonConverter` and add it to the list of Converters on the `JsonSerializerOptions` that I pass to the Serialize() method like so: ``` var options = new JsonSerializerOptions(); options.Converters.Add(new BookConverter()); json = JsonSerializer.Serialize(book, options); ``` In the JsonConverter I would have to write the entire JSON representation myself using a `Utf8JsonWriter`, excluding the property I don't want to serialize. This is a lot of work to just be able to exclude a property. While the JsonConverter is a great extensibility feature from the .NET team, its just too low-level for my use case. Does anyone know of any other way to acheive the exclusion of the property without having to write out the JSON representation myself? I don't want to have to do the following: - Use an attribute, or dynamically add an attribute at runtime - Change the access modifier of the property to something like `private` or `protected` - Use a 3rd party library, as my issue is solvable if I use Json.NET. Example: ``` class Program { void Main() { // We want to serialize Book but to ignore the Author property var book = new Book() { Id = 1, Name = "Calculus", Author = new Author() }; var json = JsonSerializer.Serialize(book); // Default serialization, we get this: // json = { "Id": 1, "Name": "Calculus", "Author": {} } // Add our custom converter to options and pass it to the Serialize() method var options = new JsonSerializerOptions(); options.Converters.Add(new BookConverter()); json = JsonSerializer.Serialize(book, options); // I want to get this: // json = { Id: 1, Name: "Calculus" } } } public class Author { } public class Book { public int Id { get; set; } public string Name { get; set; } public Author Author { get; set; } } public class BookConverter : JsonConverter<Book> { public override Book Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // Use default implementation when deserializing (reading) return JsonSerializer.Deserialize<Book>(ref reader, options); } public override void Write(Utf8JsonWriter writer, Book value, JsonSerializerOptions options) { // Serializing. Here we have to write the JSON representation ourselves writer.WriteStartObject(); writer.WriteNumber("Id", value.Id); writer.WriteString("Name", value.Name); // Don't write Author so we can exclude it writer.WriteEndObject(); } } ```

Original source

Related problems