JSON Serialize ignorare proprietà a runtime

In questo post descrivo come escludere a runtime una o più proprietà di un oggetto dalla serializzazione in formato json utilizzando la libreria System.Text.Json.

Consideriamo un oggetto di tipo Book così definito:


public class Book
{
    public int Id { get; set; }
    public string? Title { get; set; }
    public int? Pages { get; set; }
    public string? Author { get; set; }
    public string Language { get; set; }
    public int PubYear { get; set; }
}

Questo il codice per serializzare in formato json un’istanza della classe Book:


var book = new Book
{
    Id = 1,
    Title = "Pensieri lenti e veloci",
    Pages = 684,
    Author = "Daniel Kahneman",
    Language = "Italiano",
    PubYear = 2020
};

var json = JsonSerializer.Serialize(book,
    new JsonSerializerOptions { WriteIndented = true }
);

Console.WriteLine(json);

Questo sarà il risultato dell’oggetto in formato json.

{
    "Id": 1,
    "Title": "Pensieri lenti e veloci",
    "Pages": 684,
    "Author": "Daniel Kahneman",
    "Language": "Italiano",
    "PubYear": 2020
}

Se si vuole ignorare una proprietà di un oggetto dalla serializzazione si può utilizzare l’attributo [JsonIgnore] su ogni proprietà da escludere.


public class Book
{
    [JsonIgnore]
    public int Id { get; set; }
    public string? Title { get; set; }
    public int? Pages { get; set; }
    public string? Author { get; set; }
    public string Language { get; set; }
    public int PubYear { get; set; }
}

In questo modo ogni volta che un oggetto di quel tipo verrà serializzato, il contenuto della proprietà con attributo [JsonIgnore] non verrà incluso nel risultato.


var book = new Book
{
    Id = 1,
    Title = "Pensieri lenti e veloci",
    Pages = 684,
    Author = "Daniel Kahneman",
    Language = "Italiano",
    PubYear = 2020
};

var json = JsonSerializer.Serialize(book,
    new JsonSerializerOptions { WriteIndented = true }
);

Console.WriteLine(json);

Questo sarà il risultato dell’oggetto in formato json con la proprietà Id che è stata ignorata dalla serializzazione.

{
    "Title": "Pensieri lenti e veloci",
    "Pages": 684,
    "Author": "Daniel Kahneman",
    "Language": "Italiano",
    "PubYear": 2020
}

L’utilizzo dell’attributo [JsonIgnore] è un’operazione eseguita a design time perchè si conosce a priori quali proprietà andranno serializzate e quali no.

Ma se si vuole ignorare una proprietà a runtime, nonostante la proprietà non abbia l’attributo [JsonIgnore] allora è necessario scegliere un percorso diverso.


public class JsonIgnoreProperties
{
    private readonly List<string> _ignoredNames = new List<string>();
    private readonly Type _type;

    public JsonIgnoreProperties(Type objType)
    {
        _type = objType;
    }

    public void IgnoreProperty(string name)
    {
        _ignoredNames.Add(name);
    }

    public void ModifyTypeInfo(JsonTypeInfo ti)
    {
        if (ti.Type != _type)
        {
            return;
        }

        JsonPropertyInfo[] props = ti.Properties.Where(
            (pi) => !_ignoredNames.Contains(pi.Name)
        ).ToArray();

        ti.Properties.Clear();

        foreach (var pi in props)
        {
            ti.Properties.Add(pi);
        }
    }
}

A questo punto la classe JsonIgnoreProperties va instanziata ed utilizzata in questo modo:


var book = new Book
{
    Id = 1,
    Title = "Pensieri lenti e veloci",
    Pages = 684,
    Author = "Daniel Kahneman",
    Language = "Italiano",
    PubYear = 2020
};

var modifier = new JsonIgnoreProperties(typeof(Book));
modifier.IgnoreProperty("Language");

JsonSerializerOptions options = new()
{
    TypeInfoResolver = new DefaultJsonTypeInfoResolver()
    {
        Modifiers = { modifier.ModifyTypeInfo }
    },
    WriteIndented = true
};

var json = JsonSerializer.Serialize(book, options);
Console.WriteLine(json);

Ecco il risultato in formato json con le seguenti proprietà escluse dalla serializzazione:

  • Id esclusa grazie all’attributo [JsonIgnore]
  • Language esclusa grazie alla classe JsonIgnoreProperties
{
    "Title": "Pensieri lenti e veloci",
    "Pages": 684,
    "Author": "Daniel Kahneman",
    "PubYear": 2020
}