1. Introduction
Pendant longtemps dans l'écosystème .NET, l'outil principal pour travailler avec JSON était l'excellent paquet tiers Newtonsoft.Json (aussi appelé Json.NET). Il est puissant, flexible, et est encore largement utilisé. Mais avec l'arrivée des nouvelles versions .NET 9 et C# 14, Microsoft a décidé qu'il était temps d'avoir son propre sérialiseur JSON intégré et haute performance. C'est ainsi qu'est né System.Text.Json.
Pourquoi une nouvelle approche ? System.Text.Json a été conçu en tenant compte des réalités modernes et résout des problèmes accumulés avec les bibliothèques tierces. Il est optimisé pour la vitesse et la sécurité, s'adapte bien aux scénarios asynchrones et aux web-API, et — le meilleur — il ne nécessite pas d'installation via NuGet : tout est déjà dans la plateforme.
Bien sûr, Newtonsoft.Json n'a pas disparu, et nous le verrons plus tard. Mais pour la plupart des nouveaux projets, System.Text.Json est le choix par défaut. Préparez-vous, on va apprendre à faire parler nos objets en JSON !
2. Principes de base de System.Text.Json
Sérialisation simple d'un objet
Allez, commençons par la magie de base. Sérialisons notre objet en chaîne JSON.
using System;
using System.Text.Json; // N'oubliez pas d'ajouter !
public class Player
{
public string Name { get; set; }
public int Health { get; set; }
public bool IsAlive { get; set; }
}
// Quelque part dans votre programme :
Player player = new Player { Name = "Aragorn", Health = 100, IsAlive = true };
// Sérialisation :
string json = JsonSerializer.Serialize(player);
Console.WriteLine(json); // Affichera : {"Name":"Aragorn","Health":100,"IsAlive":true}
Commentaire : Si vous commencez juste à apprendre la sérialisation, cet exemple montre comme c'est simple : JsonSerializer.Serialize — et voilà.
Désérialisation d'un objet
Ranimons un objet à partir d'une chaîne JSON :
string incomingJson = "{\"Name\":\"Legolas\",\"Health\":88,\"IsAlive\":true}";
Player player2 = JsonSerializer.Deserialize<Player>(incomingJson);
Console.WriteLine(player2.Name); // Legolas
Console.WriteLine(player2.Health); // 88
Console.WriteLine(player2.IsAlive); // true
Commentaire : Si la structure JSON correspond à votre classe — tout fonctionne comme une horloge. Sinon — vous pouvez avoir des exceptions ou des valeurs par défaut.
3. Principes de fonctionnement et architecture de la sérialisation
Comment se fait le mapping
System.Text.Json utilise par défaut les mêmes noms de propriétés que dans la classe. La casse compte ! Si dans le JSON il est écrit health au lieu de Health, la désérialisation ne fonctionnera pas — la propriété restera avec sa valeur par défaut (0, false ou null).
Par exemple :
// JSON avec des clés en minuscules :
string badJson = "{\"name\":\"Gimli\",\"health\":120,\"isAlive\":true}";
Player player3 = JsonSerializer.Deserialize<Player>(badJson);
Console.WriteLine(player3.Name); // vide
Console.WriteLine(player3.Health); // 0
Console.WriteLine(player3.IsAlive); // false
Fait amusant : Beaucoup d'API écrivent les clés en camelCase (health), alors qu'en C# on utilise PascalCase (Health). On règle ça avec des options (ci-dessous).
4. Contrôle de la sérialisation — options et réglages
Formatage JSON : sortie "lisible par un humain"
Parfois on veut un JSON pas compact mais bien formaté — pour des configs ou des logs.
var options = new JsonSerializerOptions
{
WriteIndented = true // Ajouter des indentations
};
string prettyJson = JsonSerializer.Serialize(player, options);
Console.WriteLine(prettyJson);
/*
{
"Name": "Frodo",
"Health": 50,
"IsAlive": true,
"Inventory": [
"Ring",
"Bread",
"Torch"
],
"Position": {
"X": 5,
"Y": 15
}
}
*/
On utilise la propriété WriteIndented, et le sérialiseur ajoute indentations et retours à la ligne.
Contrôler le style des noms (CamelCase vs PascalCase)
Si vous travaillez avec une web-API où toutes les clés sont en camelCase, activez la politique de nommage :
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
string camelCaseJson = JsonSerializer.Serialize(player, options);
// {"name":"Frodo","health":50,"isAlive":true,"inventory":["Ring","Bread","Torch"],"position":{"x":5,"y":15}}
Alors à la désérialisation ces clés seront correctement mappées :
string apiJson = "{\"name\":\"Bilbo\",\"health\":40,\"isAlive\":true,\"inventory\":[\"Mug\"],\"position\":{\"x\":10,\"y\":5}}";
Player bilbo = JsonSerializer.Deserialize<Player>(apiJson, options);
Console.WriteLine(bilbo.Name); // Bilbo
5. Subtilités utiles
Utiliser l'attribut [JsonIgnore]
Parfois on ne veut pas sérialiser toutes les propriétés — par exemple des données privées ou des valeurs calculées temporaires.
using System.Text.Json.Serialization;
public class Player
{
public string Name { get; set; }
public int Health { get; set; }
[JsonIgnore] // Cette propriété n'apparaîtra pas dans le JSON
public bool IsSecretCharacter { get; set; }
}
Maintenant lors de la sérialisation :
var player = new Player { Name = "Boromir", Health = 80, IsSecretCharacter = true };
string json = JsonSerializer.Serialize(player);
Console.WriteLine(json); // {"Name":"Boromir","Health":80}
À la désérialisation inverse IsSecretCharacter obtiendra la valeur par défaut (false).
Utiliser [JsonPropertyName("...")]
Supposons que dans le code la propriété s'appelle IsAlive, mais dans le JSON elle doit être "status" :
using System.Text.Json.Serialization;
public class Player
{
public string Name { get; set; }
public int Health { get; set; }
[JsonPropertyName("status")]
public bool IsAlive { get; set; }
}
La sérialisation ressemblera maintenant à ça :
var player = new Player { Name = "Pippin", Health = 60, IsAlive = false };
string json = JsonSerializer.Serialize(player);
Console.WriteLine(json); // {"Name":"Pippin","Health":60,"status":false}
Et à la désérialisation la clé "status" remplira correctement la propriété IsAlive.
Limitations intégrées et particularités de sécurité
- Par défaut, seules les propriétés publiques avec getters/setters sont sérialisées ; les champs/propriétés privées sont ignorés.
- Pour les références cycliques, une exception est levée : "A possible object cycle was detected".
- Contrairement à Newtonsoft.Json, le sérialiseur standard mise moins sur des astuces "magiques" avec les types — en contrepartie il est plus sûr et plus rapide pour les scénarios courants.
6. Erreurs fréquentes et pièges
Vous changez accidentellement le nom d'une propriété dans le JSON et oubliez de mettre à jour le code — en résultat la propriété reçoit la valeur par défaut (null, 0, false).
Le champ nécessaire est absent du JSON — la propriété correspondante de l'objet restera par défaut (voir la documentation).
La propriété n'a pas de setter public — elle ne sera pas remplie à la désérialisation.
Vous changez la structure des classes imbriquées ou des collections — la désérialisation peut casser ou donner des résultats inattendus.
Des noms identiques à différents niveaux d'imbrication (dans le parent et l'objet enfant) embrouillent et compliquent le débuggage.
Parfois la cause est la version de la plateforme : les anciennes versions de System.Text.Json géraient moins bien certains types (par exemple, Dictionary, DateTime, enum), mais en .NET 7/8/9 beaucoup de choses ont été corrigées.
GO TO FULL VERSION