Migrer de Newtonsoft.Json vers System.Text.Json
Cet article explique comment migrer de Newtonsoft.Json vers System.Text.Json.
L’espace de noms System.Text.Json
fournit des fonctionnalités de sérialisation vers et de désérialisation à partir de JavaScript Object Notation (JSON). La bibliothèque System.Text.Json
est incluse dans le runtime pour .NET Core 3.1 (et les versions ultérieures). Pour d’autres frameworks cibles, installez le package NuGet System.Text.Json. Le package prend en charge :
- .NET Standard 2.0 et versions ultérieures
- .NET Framework 4.6.2 et versions ultérieures
- .NET Core 2.0, 2.1 et 2.2
Conseil
Vous pouvez utiliser l’assistance IA pour migrer depuis Newtonsoft.Json
avec GitHub Copilot.
System.Text.Json
se concentre principalement sur les performances, la sécurité et la conformité aux normes. Il présente des différences clés dans le comportement par défaut et ne vise pas à avoir la parité des fonctionnalités avec Newtonsoft.Json
. Pour certains scénarios, System.Text.Json
n’offre actuellement aucune fonctionnalité intégrée, mais il existe des solutions de contournement recommandées. Pour les autres scénarios, les solutions de contournement sont peu pratiques.
L'équipe System.Text.Json
investit dans l'ajout des fonctionnalités les plus souvent demandées. Si votre application dépend d’une fonctionnalité manquante, envisagez de signaler un problème dans le référentiel GitHub dotnet/runtime pour savoir si la prise en charge de votre scénario peut être ajoutée.
La majeure partie de cet article traite de l’utilisation de l’API JsonSerializer, mais il inclut également des conseils sur l’utilisation des types JsonDocument (qui représente le Document Object Model, ou DOM), Utf8JsonReader et Utf8JsonWriter.
En Visual Basic, vous ne pouvez pas utiliser Utf8JsonReader, ce qui signifie également que vous ne pouvez pas écrire de convertisseurs personnalisés. La plupart des solutions de contournement présentées ici nécessitent l’écriture de convertisseurs personnalisés. Vous pouvez écrire un convertisseur personnalisé en C# et l’inscrire dans un projet Visual Basic. Pour plus d’informations, consultez le Support Visual Basic.
Tableau des différences
Le tableau suivant répertorie les fonctionnalités de Newtonsoft.Json
et les équivalents System.Text.Json
. Les équivalents sont répartis dans les catégories suivantes :
- ✔️ Pris en charge par la fonctionnalité intégrée. L’obtention d’un comportement similaire à partir de
System.Text.Json
peut nécessiter l’utilisation d’un attribut ou d’une option globale. - ⚠️ Non pris en charge, mais une solution de contournement existe. Les solutions de contournement sont des convertisseurs personnalisés, qui peuvent ne pas fournir une parité complète avec les fonctionnalités de
Newtonsoft.Json
. Dans certains de ces cas, l’exemple de code est fourni en tant qu’exempls. Si vous vous appuyez sur ces fonctionnalités deNewtonsoft.Json
, la migration nécessite des modifications à vos modèles d’objet .NET ou d’autres modifications de code. - ❌ Non pris en charge, et la solution de contournement n’est pas pratique ou possible. Si vous vous appuyez sur ces fonctionnalités de
Newtonsoft.Json
, la migration ne sera pas possible sans modifications significatives.
Fonctionnalité Newtonsoft.Json | Équivalent System.Text.Json |
---|---|
Désérialisation non sensible à la casse par défaut | ✔️ Paramètre global PropertyNameCaseInsensitive |
Noms des propriétés en camel-case | ✔️ Paramètre global PropertyNamingPolicy |
Noms de propriétés cas avec tirets | ✔️ Stratégie d’affectation de noms avec des tirets |
Échappement de caractères minimal | ✔️ Échappement de caractères strict, configurable |
Paramètre global NullValueHandling.Ignore |
✔️ Option globale DefaultIgnoreCondition |
Autoriser les commentaires | ✔️ Paramètre global ReadCommentHandling |
Autoriser les virgules de fin | ✔️ Paramètre global AllowTrailingCommas |
Inscription de convertisseur personnalisé | ✔️ L’ordre de priorité diffère |
Profondeur maximale par défaut de 64, configurable | ✔️ Profondeur maximale par défaut 64, configurable |
Paramètre global PreserveReferencesHandling |
✔️ Paramètre global ReferenceHandling |
Sérialiser ou désérialiser des nombres entre guillemets | ✔️ Paramètre global NumberHandling, attribut [JsonNumberHandling] |
Désérialiser en classes et structs immuables | ✔️ JsonConstructor, C# 9 Enregistrements |
Prise en charge des champs | ✔️ Paramètre global IncludeFields, attribut [JsonInclude] |
Paramètre global DefaultValueHandling |
✔️ Paramètre global DefaultIgnoreCondition |
Paramètre NullValueHandling sur [JsonProperty] |
✔️ Attribut JsonIgnore |
Paramètre DefaultValueHandling sur [JsonProperty] |
✔️ Attribut JsonIgnore |
Désérialiser Dictionary avec une clé non chaîne |
✔️ Pris en charge |
Prise en charge des setters et getters de propriétés non publiques | ✔️ Attribut JsonInclude |
Attribut [JsonConstructor] |
✔️ Attribut [JsonConstructor] |
Paramètre global ReferenceLoopHandling |
✔️ Paramètre global ReferenceHandling |
Rappels | ✔️ Rappels |
NaN, Infinity, -Infinity | ✔️ Pris en charge |
Paramètre Required sur l’attribut [JsonProperty] |
✔️ Attribut [JsonRequired] et modificateur C# requis |
DefaultContractResolver pour ignorer les propriétés |
✔️ Classe DefaultJsonTypeInfoResolver |
Sérialisation polymorphe | ✔️ Attribut [JsonDerivedType] |
Désérialisation polymorphe | ✔️ Discriminateur de type sur l’attribut [JsonDerivedType] |
Désérialiser la valeur d’une énumération de chaîne | ✔️ Désérialiser les valeurs d’une énumération de chaîne |
Paramètre global MissingMemberHandling |
✔️ Gérer des membres manquants |
Remplir les propriétés sans aucun setter | ✔️ Remplir les propriétés sans aucun setter |
Paramètre global ObjectCreationHandling |
✔️ Réutiliser plutôt que remplacer les propriétés |
Prise en charge d’un large éventail de types | ⚠️ Certains types nécessitent des convertisseurs personnalisés |
Désérialiser le type déduit en propriétés object |
⚠️ Non pris en charge, solution de contournement, exemple |
Désérialiser le littéral JSON null en types valeur non nullables |
⚠️ Non pris en charge, solution de contournement, exemple |
Paramètres DateTimeZoneHandling , DateFormatString |
⚠️ Non pris en charge, solution de contournement, exemple |
Méthode JsonConvert.PopulateObject |
⚠️ Non pris en charge, solution de contournement |
Prise en charge des attributs System.Runtime.Serialization |
⚠️ Non pris en charge, solution de contournement, exemple |
JsonObjectAttribute |
⚠️ Non pris en charge, solution de contournement |
Autorisation des noms de propriétés sans guillemets | ❌Non pris en charge par conception |
Autorisation des guillemets uniques autour des valeurs de chaîne | ❌Non pris en charge par conception |
Autorisation des valeurs JSON autres que les chaînes pour les propriétés de chaîne | ❌Non pris en charge par conception |
Paramètre global TypeNameHandling.All |
❌Non pris en charge par conception |
Prise en charge des requêtes JsonPath |
❌Non pris en charge |
Limites configurables | ❌Non pris en charge |
Fonctionnalité Newtonsoft.Json | Équivalent System.Text.Json |
---|---|
Désérialisation non sensible à la casse par défaut | ✔️ Paramètre global PropertyNameCaseInsensitive |
Noms des propriétés en camel-case | ✔️ Paramètre global PropertyNamingPolicy |
Échappement de caractères minimal | ✔️ Échappement de caractères strict, configurable |
Paramètre global NullValueHandling.Ignore |
✔️ Option globale DefaultIgnoreCondition |
Autoriser les commentaires | ✔️ Paramètre global ReadCommentHandling |
Autoriser les virgules de fin | ✔️ Paramètre global AllowTrailingCommas |
Inscription de convertisseur personnalisé | ✔️ L’ordre de priorité diffère |
Profondeur maximale par défaut de 64, configurable | ✔️ Profondeur maximale par défaut 64, configurable |
Paramètre global PreserveReferencesHandling |
✔️ Paramètre global ReferenceHandling |
Sérialiser ou désérialiser des nombres entre guillemets | ✔️ Paramètre global NumberHandling, attribut [JsonNumberHandling] |
Désérialiser en classes et structs immuables | ✔️ JsonConstructor, C# 9 Enregistrements |
Prise en charge des champs | ✔️ Paramètre global IncludeFields, attribut [JsonInclude] |
Paramètre global DefaultValueHandling |
✔️ Paramètre global DefaultIgnoreCondition |
Paramètre NullValueHandling sur [JsonProperty] |
✔️ Attribut JsonIgnore |
Paramètre DefaultValueHandling sur [JsonProperty] |
✔️ Attribut JsonIgnore |
Désérialiser Dictionary avec une clé non chaîne |
✔️ Pris en charge |
Prise en charge des setters et getters de propriétés non publiques | ✔️ Attribut JsonInclude |
Attribut [JsonConstructor] |
✔️ Attribut [JsonConstructor] |
Paramètre global ReferenceLoopHandling |
✔️ Paramètre global ReferenceHandling |
Rappels | ✔️ Rappels |
NaN, Infinity, -Infinity | ✔️ Pris en charge |
Paramètre Required sur l’attribut [JsonProperty] |
✔️ Attribut [JsonRequired] et modificateur C# requis |
DefaultContractResolver pour ignorer les propriétés |
✔️ Classe DefaultJsonTypeInfoResolver |
Sérialisation polymorphe | ✔️ Attribut [JsonDerivedType] |
Désérialisation polymorphe | ✔️ Discriminateur de type sur l’attribut [JsonDerivedType] |
Désérialiser la valeur d’une énumération de chaîne | ✔️ Désérialiser les valeurs d’une énumération de chaîne |
Prise en charge d’un large éventail de types | ⚠️ Certains types nécessitent des convertisseurs personnalisés |
Désérialiser le type déduit en propriétés object |
⚠️ Non pris en charge, solution de contournement, exemple |
Désérialiser le littéral JSON null en types valeur non nullables |
⚠️ Non pris en charge, solution de contournement, exemple |
Paramètres DateTimeZoneHandling , DateFormatString |
⚠️ Non pris en charge, solution de contournement, exemple |
Méthode JsonConvert.PopulateObject |
⚠️ Non pris en charge, solution de contournement |
Paramètre global ObjectCreationHandling |
⚠️ Non pris en charge, solution de contournement |
Ajouter aux collections sans setters | ⚠️ Non pris en charge, solution de contournement |
Noms de propriétés cas avec tirets | ⚠️ Non pris en charge, solution de contournement |
Prise en charge des attributs System.Runtime.Serialization |
⚠️ Non pris en charge, solution de contournement, exemple |
Paramètre global MissingMemberHandling |
⚠️ Non pris en charge, solution de contournement, exemple |
JsonObjectAttribute |
⚠️ Non pris en charge, solution de contournement |
Autorisation des noms de propriétés sans guillemets | ❌Non pris en charge par conception |
Autorisation des guillemets uniques autour des valeurs de chaîne | ❌Non pris en charge par conception |
Autorisation des valeurs JSON autres que les chaînes pour les propriétés de chaîne | ❌Non pris en charge par conception |
Paramètre global TypeNameHandling.All |
❌Non pris en charge par conception |
Prise en charge des requêtes JsonPath |
❌Non pris en charge |
Limites configurables | ❌Non pris en charge |
Fonctionnalité Newtonsoft.Json | Équivalent System.Text.Json |
---|---|
Désérialisation non sensible à la casse par défaut | ✔️ Paramètre global PropertyNameCaseInsensitive |
Noms des propriétés en camel-case | ✔️ Paramètre global PropertyNamingPolicy |
Échappement de caractères minimal | ✔️ Échappement de caractères strict, configurable |
Paramètre global NullValueHandling.Ignore |
✔️ Option globale DefaultIgnoreCondition |
Autoriser les commentaires | ✔️ Paramètre global ReadCommentHandling |
Autoriser les virgules de fin | ✔️ Paramètre global AllowTrailingCommas |
Inscription de convertisseur personnalisé | ✔️ L’ordre de priorité diffère |
Profondeur maximale par défaut de 64, configurable | ✔️ Profondeur maximale par défaut 64, configurable |
Paramètre global PreserveReferencesHandling |
✔️ Paramètre global ReferenceHandling |
Sérialiser ou désérialiser des nombres entre guillemets | ✔️ Paramètre global NumberHandling, attribut [JsonNumberHandling] |
Désérialiser en classes et structs immuables | ✔️ JsonConstructor, C# 9 Enregistrements |
Prise en charge des champs | ✔️ Paramètre global IncludeFields, attribut [JsonInclude] |
Paramètre global DefaultValueHandling |
✔️ Paramètre global DefaultIgnoreCondition |
Paramètre NullValueHandling sur [JsonProperty] |
✔️ Attribut JsonIgnore |
Paramètre DefaultValueHandling sur [JsonProperty] |
✔️ Attribut JsonIgnore |
Désérialiser Dictionary avec une clé non chaîne |
✔️ Pris en charge |
Prise en charge des setters et getters de propriétés non publiques | ✔️ Attribut JsonInclude |
Attribut [JsonConstructor] |
✔️ Attribut [JsonConstructor] |
Paramètre global ReferenceLoopHandling |
✔️ Paramètre global ReferenceHandling |
Rappels | ✔️ Rappels |
NaN, Infinity, -Infinity | ✔️ Pris en charge |
Désérialiser la valeur d’une énumération de chaîne | ✔️ Désérialiser les valeurs d’une énumération de chaîne |
Prise en charge d’un large éventail de types | ⚠️ Certains types nécessitent des convertisseurs personnalisés |
Sérialisation polymorphe | ⚠️ Non pris en charge, solution de contournement, exemple |
Désérialisation polymorphe | ⚠️ Non pris en charge, solution de contournement, exemple |
Désérialiser le type déduit en propriétés object |
⚠️ Non pris en charge, solution de contournement, exemple |
Désérialiser le littéral JSON null en types valeur non nullables |
⚠️ Non pris en charge, solution de contournement, exemple |
Paramètre Required sur l’attribut [JsonProperty] |
⚠️ Non pris en charge, solution de contournement, exemple |
DefaultContractResolver pour ignorer les propriétés |
⚠️ Non pris en charge, solution de contournement, exemple |
Paramètres DateTimeZoneHandling , DateFormatString |
⚠️ Non pris en charge, solution de contournement, exemple |
Méthode JsonConvert.PopulateObject |
⚠️ Non pris en charge, solution de contournement |
Paramètre global ObjectCreationHandling |
⚠️ Non pris en charge, solution de contournement |
Ajouter aux collections sans setters | ⚠️ Non pris en charge, solution de contournement |
Noms de propriétés cas avec tirets | ⚠️ Non pris en charge, solution de contournement |
JsonObjectAttribute |
⚠️ Non pris en charge, solution de contournement |
Prise en charge des attributs System.Runtime.Serialization |
❌Non pris en charge |
Paramètre global MissingMemberHandling |
❌Non pris en charge |
Autorisation des noms de propriétés sans guillemets | ❌Non pris en charge par conception |
Autorisation des guillemets uniques autour des valeurs de chaîne | ❌Non pris en charge par conception |
Autorisation des valeurs JSON autres que les chaînes pour les propriétés de chaîne | ❌Non pris en charge par conception |
Paramètre global TypeNameHandling.All |
❌Non pris en charge par conception |
Prise en charge des requêtes JsonPath |
❌Non pris en charge |
Limites configurables | ❌Non pris en charge |
Il ne s’agit pas d’une liste exhaustive des fonctionnalités de Newtonsoft.Json
. La liste inclut de nombreux scénarios qui ont été demandés dans des problèmes GitHub ou des messages sur StackOverflow. Si vous implémentez une solution de contournement pour l’un des scénarios répertoriés ici et que vous ne disposez pas actuellement d’un exemple de code, et si vous souhaitez partager votre solution, sélectionnez Cette page dans la section Commentaires en bas de cette page. Cela crée un problème dans le référentiel GitHub de cette documentation et le répertorie également dans la section Commentaires de cette page.
Différences dans le comportement par défaut
System.Text.Json est strict par défaut et évite toute estimation ou interprétation au nom de l’appelant, en mettant l’accent sur le comportement déterministe. La bibliothèque est intentionnellement conçue de cette façon à des fins de performances et de sécurité. Newtonsoft.Json
est flexible par défaut. Cette différence fondamentale dans la conception est à l’origine de la plupart des différences spécifiques suivantes dans le comportement par défaut.
Désérialisation non sensible à la casse
Pendant la désérialisation, Newtonsoft.Json
ne respecte pas la casse par défaut lors de la mise en correspondance. System.Text.Json est par défaut sensible à la casse, ce qui offre de meilleures performances, car elle effectue une correspondance exacte. Pour plus d’informations sur la façon d’effectuer une correspondance sans respect de la casse, consultez Correspondance de propriétés sans respect de la casse.
Si vous utilisez System.Text.Json
indirectement en utilisant ASP.NET Core, vous n’avez rien à faire pour obtenir un comportement comme Newtonsoft.Json
. ASP.NET Core spécifie les paramètres pour les noms de propriétés à casse mixte et la correspondance ne respectant pas la casse lorsqu’il utilise System.Text.Json
.
ASP.NET Core permet également la désérialisation des nombres entre guillemets par défaut.
Échappement de caractères minimal
Pendant la sérialisation, Newtonsoft.Json
est relativement permissif pour ce qui est de laisser passer des caractères sans les échapper. Autrement dit, il ne les remplace pas par \uxxxx
, où xxxx
est le point de code du caractère. Lorsqu’il les échappe, il le fait en émettant un \
avant le caractère (par exemple, "
devient \"
). System.Text.Json échappe davantage de caractères par défaut pour fournir des protections de défense en profondeur contre les attaques de scripting inter-site (XSS) ou de divulgation d’informations, et le fait à l’aide de la séquence de six caractères. System.Text.Json
échappe tous les caractères non ASCII par défaut. Vous n’avez donc rien à faire si vous utilisez StringEscapeHandling.EscapeNonAscii
dans Newtonsoft.Json
. System.Text.Json
permet également d’échapper les caractères HTML, par défaut. Pour plus d’informations sur la façon de remplacer le comportement par défaut de System.Text.Json
, consultez Personnaliser l’encodage de caractères.
Commentaires
Pendant la désérialisation, Newtonsoft.Json
ignore les commentaires dans le JSON par défaut. Par défaut, System.Text.Json lève des exceptions pour les commentaires, car la spécification RFC 8259 ne les inclut pas. Pour plus d’informations sur l’autorisation des commentaires, consultez Autoriser les commentaires et les virgules de fin.
Virgules de fin
Pendant la désérialisation, Newtonsoft.Json
ignore les virgules de fin par défaut. Il ignore également les virgules de fin multiples (par exemple, [{"Color":"Red"},{"Color":"Green"},,]
). Par défaut, System.Text.Json lève des exceptions pour les virgules de fin, car la spécification RFC 8259 ne les autorise pas. Pour plus d’informations sur la façon d’obliger System.Text.Json
à les accepter, consultez Autoriser les commentaires et les virgules de fin. Il n’existe aucun moyen d’autoriser les virgules de fin multiples.
Priorité d’inscription du convertisseur
La priorité d’inscription Newtonsoft.Json
pour les convertisseurs personnalisés est la suivante :
- Attribut sur la propriété
- Attribut sur le type
- Collection Converters
Cet ordre signifie qu’un convertisseur personnalisé dans la collection Converters
est remplacé par un convertisseur inscrit en appliquant un attribut au niveau du type. Ces deux inscriptions sont remplacées par un attribut au niveau de la propriété.
La priorité d’inscription System.Text.Json pour les convertisseurs personnalisés est différente :
- Attribut sur la propriété
- Converterscollection
- Attribut sur le type
La différence est qu’un convertisseur personnalisé dans la collection Converters
remplace un attribut au niveau du type. L’objectif de cet ordre de priorité est de faire en sorte que les modifications au moment de l’exécution remplacent les choix au moment de la conception. Il n’existe aucun moyen de modifier la priorité.
Pour plus d’informations sur l’inscription d’un convertisseur personnalisé, consultez Inscrire un convertisseur personnalisé.
Profondeur maximale
La dernière version de Newtonsoft.Json
a une limite de profondeur maximale de 64 par défaut. System.Text.Json a également une limite par défaut de 64, et elle est configurable en définissant JsonSerializerOptions.MaxDepth.
Si vous utilisez System.Text.Json
indirectement en utilisant ASP.NET Core, la limite de profondeur maximale par défaut est de 32. La valeur par défaut est la même que pour la liaison de modèle et est définie dans la classe JsonOptions.
Chaînes JSON (noms de propriétés et valeurs de chaîne)
Pendant la désérialisation, Newtonsoft.Json
accepte les noms de propriétés entourés de guillemets doubles, de guillemets simples ou sans guillemets. Il accepte les valeurs de chaîne entourées de guillemets doubles ou de guillemets simples. Par exemple, Newtonsoft.Json
accepte le JSON suivant :
{
"name1": "value",
'name2': "value",
name3: 'value'
}
System.Text.Json
Accepte uniquement les noms de propriétés et les valeurs de chaîne entre guillemets doubles, car ce format est requis par la spécification RFC 8259 et est le seul format considéré comme du JSON valide.
Une valeur placée entre guillemets simples entraîne une exception JsonException avec le message suivant :
''' is an invalid start of a value.
Valeurs autres que des chaînes pour les propriétés de chaîne
Newtonsoft.Json
accepte des valeurs autres que des chaînes, comme un nombre ou les littéraux true
et false
, pour la désérialisation vers les propriétés de type chaîne. Voici un exemple de JSON que Newtonsoft.Json
désérialise correctement en la classe suivante :
{
"String1": 1,
"String2": true,
"String3": false
}
public class ExampleClass
{
public string String1 { get; set; }
public string String2 { get; set; }
public string String3 { get; set; }
}
System.Text.Json
ne désérialise pas les valeurs autres que les chaînes en propriétés de chaîne. Une valeur autre que la chaîne reçue pour un champ de chaîne entraîne une exception JsonException avec le message suivant :
The JSON value could not be converted to System.String.
Scénarios utilisant JsonSerializer
Certains des scénarios suivants ne sont pas pris en charge par les fonctionnalités intégrées, mais des solutions de contournement sont possibles. Les solutions de contournement sont des convertisseurs personnalisés, qui peuvent ne pas fournir une parité complète avec les fonctionnalités de Newtonsoft.Json
. Dans certains de ces cas, l’exemple de code est fourni en tant qu’exempls. Si vous vous appuyez sur ces fonctionnalités de Newtonsoft.Json
, la migration nécessite des modifications à vos modèles d’objet .NET ou d’autres modifications de code.
Pour certains des scénarios suivants, les solutions de contournement ne sont pas pratiques ou possibles. Si vous vous appuyez sur ces fonctionnalités de Newtonsoft.Json
, la migration ne sera pas possible sans modifications significatives.
Autoriser ou écrire des nombres entre guillemets
Newtonsoft.Json
peut sérialiser ou désérialiser des nombres représentés par des chaînes JSON (entourées de guillemets). Par exemple, il peut accepter {"DegreesCelsius":"23"}
au lieu de {"DegreesCelsius":23}
. Pour activer ce comportement dans System.Text.Json, définissez JsonSerializerOptions.NumberHandling sur WriteAsString ou AllowReadingFromString, ou utilisez l’attribut [JsonNumberHandling].
Si vous utilisez System.Text.Json
indirectement en utilisant ASP.NET Core, vous n’avez rien à faire pour obtenir un comportement comme Newtonsoft.Json
. ASP.NET Core spécifie les valeurs web par défaut lorsqu’il utilise System.Text.Json
, et les valeurs par défaut web autorisent les nombres entre guillemets.
Pour plus d’informations, consultez Autoriser ou écrire des nombres entre guillemets.
Spécifier le constructeur à utiliser lors de la désérialisation
L’attribut Newtonsoft.Json
[JsonConstructor]
vous permet de spécifier le constructeur à appeler lors de la désérialisation d’un objet CLR traditionnel.
System.Text.Json
a également un attribut [JsonConstructor]. Pour plus d’informations, consultez Types et enregistrements immuables.
Ignorer une propriété de manière conditionnelle
Newtonsoft.Json
propose plusieurs façons d’ignorer de manière conditionnelle une propriété lors de la sérialisation ou de la désérialisation :
DefaultContractResolver
vous permet de sélectionner des propriétés à inclure ou à ignorer, en fonction de critères arbitraires.- Les paramètres
NullValueHandling
etDefaultValueHandling
surJsonSerializerSettings
vous permettent de spécifier que toutes les propriétés à valeur null ou valeur par défaut doivent être ignorées. - Les paramètres
NullValueHandling
etDefaultValueHandling
sur l’attribut[JsonProperty]
vous permettent de spécifier des propriétés individuelles qui doivent être ignorées lorsqu’elles sont définies sur null ou sur la valeur par défaut.
System.Text.Json fournit les méthodes suivantes pour ignorer les propriétés ou les champs lors de la sérialisation :
- L’attribut [JsonIgnore] sur une propriété entraîne l’omission de la propriété dans le JSON pendant la sérialisation.
- L’option globale IgnoreReadOnlyProperties vous permet d’ignorer toutes les propriétés en lecture seule.
- Si vous incluez des champs, l’option globale JsonSerializerOptions.IgnoreReadOnlyFields vous permet d’ignorer tous les champs en lecture seule.
- L’option globale
DefaultIgnoreCondition
vous permet d’ignorer toutes les propriétés de type valeur qui ont des valeurs par défaut, ou d’ignorer toutes les propriétés de type de référence qui ont des valeurs null.
En outre, dans .NET 7 et versions ultérieures, vous pouvez personnaliser le contrat JSON pour ignorer les propriétés en fonction de critères arbitraires. Pour plus d’informations, consultez Contrats personnalisés.
Ces options ne vous permettent pas d’ignorer les propriétés sélectionnées en fonction de critères arbitraires évalués au moment de l’exécution.
Champs publics et non publics
Newtonsoft.Json
peut sérialiser et désérialiser des champs ainsi que des propriétés.
Dans System.Text.Json, utilisez le paramètre global JsonSerializerOptions.IncludeFields ou l’attribut [JsonInclude] pour inclure des champs publics lors de la sérialisation ou de la désérialisation. Pour obtenir un exemple, consultez Inclure les champs.
Conserver les références d’objet et gérer les boucles
Par défaut, Newtonsoft.Json
sérialise par valeur. Par exemple, si un objet contient deux propriétés qui contiennent une référence au même objet Person
, les valeurs des propriétés de cet objet Person
sont dupliquées dans le JSON.
Newtonsoft.Json
a un paramètre PreserveReferencesHandling
sur JsonSerializerSettings
qui vous permet de sérialiser par référence :
- Une métadonnée d’identificateur est ajoutée au JSON créé pour le premier objet
Person
. - Le JSON créé pour le deuxième objet
Person
contient une référence à cet identificateur au lieu des valeurs de propriété.
Newtonsoft.Json
a également un paramètre ReferenceLoopHandling
qui vous permet d’ignorer les références circulaires plutôt que de lever une exception.
Pour conserver les références et gérer les références circulaires dans System.Text.Json, définissez JsonSerializerOptions.ReferenceHandler sur Preserve. Le paramètre ReferenceHandler.Preserve
équivaut à PreserveReferencesHandling
= PreserveReferencesHandling.All
dans Newtonsoft.Json
.
L’option ReferenceHandler.IgnoreCycles
a un comportement similaire à Newtonsoft.JsonReferenceLoopHandling.Ignore
. Une différence est que l’implémentation de System.Text.Json remplace les boucles de référence par le jeton JSON null
au lieu d’ignorer la référence d’objet. Pour plus d’informations, consultez Ignorer les références circulaires.
À l’instar de Newtonsoft.JsonReferenceResolver, la classe System.Text.Json.Serialization.ReferenceResolver définit le comportement de conservation des références lors de la sérialisation et de la désérialisation. Créez une classe dérivée pour spécifier un comportement personnalisé. Pour obtenir un exemple, consultez GuidReferenceResolver.
Certaines fonctionnalités associées à Newtonsoft.Json
ne sont pas prises en charge :
Pour plus d’informations, consultez Conserver les références et gérer les références circulaires.
Dictionnaire avec une clé non-chaîne
Newtonsoft.Json
et System.Text.Json
prennent tous deux en charge les collections de type Dictionary<TKey, TValue>
. Toutefois, dans System.Text.Json
, TKey
doit être un type primitif, et non un type personnalisé. Pour plus d’informations, consultez Types de clés pris en charge.
Attention
La désérialisation en Dictionary<TKey, TValue>
, où TKey
a une autre valeur que string
pourrait introduire une vulnérabilité de sécurité dans l’application consommatrice. Pour plus d’informations, consultez dotnet/runtime#4761.
Types sans prise en charge intégrée
System.Text.Json ne fournit pas de prise en charge intégrée pour les types suivants :
- DataTable et les types associés (pour plus d’informations, consultez Types de collection pris en charge)
- ExpandoObject
- TimeZoneInfo
- BigInteger
- DBNull
- Type
- ValueTuple et ses types génériques associés
Des convertisseurs personnalisés peuvent être implémentés pour les types qui n’ont pas de prise en charge intégrée.
Sérialisation polymorphe
Newtonsoft.Json
effectue automatiquement une sérialisation polymorphe. À partir de .NET 7, System.Text.Json prend en charge la sérialisation polymorphe via l’attribut JsonDerivedTypeAttribute. Pour plus d’informations, consultez Sérialiser les propriétés des classes dérivées.
Désérialisation polymorphe
Newtonsoft.Json
a un paramètre TypeNameHandling
qui ajoute des métadonnées de nom de type au JSON lors de la sérialisation. Il utilise les métadonnées lors de la désérialisation pour effectuer une désérialisation polymorphe. À partir de .NET 7, System.Text.Json s’appuie sur les informations de discriminateur de type pour effectuer une désérialisation polymorphe. Ces métadonnées sont émises dans le JSON, puis utilisées lors de la désérialisation pour déterminer s’il faut désérialiser vers le type de base ou un type dérivé. Pour plus d’informations, consultez Sérialiser les propriétés des classes dérivées.
Pour prendre en charge la désérialisation polymorphe dans les versions antérieures de .NET, créez un convertisseur comme dans l’exemple de Guide pratique pour écrire des convertisseurs personnalisés.
Désérialiser les valeurs d’une énumération de chaîne
Par défaut, System.Text.Json ne prend pas en charge la désérialisation des valeurs d’une énumération de chaîne, tandis que Newtonsoft.Json
le fait. Par exemple, le code suivant lève une JsonException :
string json = "{ \"Text\": \"Hello\", \"Enum\": \"Two\" }";
var _ = JsonSerializer.Deserialize<MyObj>(json); // Throws exception.
class MyObj
{
public string Text { get; set; } = "";
public MyEnum Enum { get; set; }
}
enum MyEnum
{
One,
Two,
Three
}
Toutefois, vous pouvez activer la désérialisation des valeurs d’une énumération de chaîne en utilisant le convertisseur JsonStringEnumConverter. Pour obtenir plus d’informations, consultez Énumérations en tant que chaînes.
Désérialisation des propriétés d’objet
Quand Newtonsoft.Json
désérialise en Object, il :
- Déduit le type des valeurs primitives dans la charge utile JSON (autre que
null
) et retourne lestring
,long
,double
,boolean
ouDateTime
stocké en tant qu’objet boxed. Les valeurs primitives sont des valeurs JSON uniques comme un nombre JSON, une chaîne,true
,false
ounull
. - Retourne un
JObject
ouJArray
pour les valeurs complexes dans la charge utile JSON. Les valeurs complexes sont des collections de paires clé-valeur JSON dans des accolades ({}
) ou des listes de valeurs entre crochets ([]
). Les propriétés et valeurs dans les accolades ou crochets peuvent avoir des propriétés ou des valeurs supplémentaires. - Retourne une référence null lorsque la charge utile a le littéral JSON
null
.
System.Text.Json stocke un JsonElement
boxed pour les valeurs primitives et complexes lors de chaque désérialisation en Object, par exemple :
- Propriété
object
. - Valeur de dictionnaire
object
. - Valeur de tableau
object
. object
racine.
Toutefois, System.Text.Json
traite null
de manière identique à Newtonsoft.Json
et retourne une référence null lorsque la charge utile contient le littéral JSON null
.
Pour implémenter l’inférence de type pour les propriétés object
, créez un convertisseur comme dans l’exemple dans Guide pratique pour écrire des convertisseurs personnalisés.
Désérialiser null en type non nullable
Newtonsoft.Json
ne lève pas d’exception dans le scénario suivant :
NullValueHandling
est défini surIgnore
, et- Pendant la désérialisation, le JSON contient une valeur null pour un type de valeur non nullable.
Dans le même scénario, System.Text.Json lève une exception. (Le paramètre de gestion de la valeur null correspondant dans System.Text.Json
est JsonSerializerOptions.IgnoreNullValues = true
.)
Si vous êtes propriétaire du type cible, la meilleure solution de contournement consiste à rendre la propriété en question nullable (par exemple en modifiant int
en int?
).
Une autre solution de contournement consiste à créer un convertisseur pour le type, comme dans l’exemple suivant qui gère les valeurs null pour les types DateTimeOffset
:
using System.Text.Json;
using System.Text.Json.Serialization;
namespace SystemTextJsonSamples
{
public class DateTimeOffsetNullHandlingConverter : JsonConverter<DateTimeOffset>
{
public override DateTimeOffset Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options) =>
reader.TokenType == JsonTokenType.Null
? default
: reader.GetDateTimeOffset();
public override void Write(
Utf8JsonWriter writer,
DateTimeOffset dateTimeValue,
JsonSerializerOptions options) =>
writer.WriteStringValue(dateTimeValue);
}
}
Inscrivez ce convertisseur personnalisé à l’aide d’un attribut sur la propriété ou en ajoutant le convertisseur à la collection Converters.
Remarque : Le convertisseur précédent gère les valeurs null différemment de Newtonsoft.Json
pour les OCT qui spécifient des valeurs par défaut. Par exemple, supposons que le code suivant représente votre objet cible :
public class WeatherForecastWithDefault
{
public WeatherForecastWithDefault()
{
Date = DateTimeOffset.Parse("2001-01-01");
Summary = "No summary";
}
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string Summary { get; set; }
}
Supposons que le code JSON suivant soit désérialisé à l’aide du convertisseur précédent :
{
"Date": null,
"TemperatureCelsius": 25,
"Summary": null
}
Après la désérialisation, la propriété Date
a la valeur 1/1/0001 (default(DateTimeOffset)
), c’est-à-dire que la valeur définie dans le constructeur est remplacée. Pour les mêmes OCT et JSON, la désérialisation de Newtonsoft.Json
laisserait 1/1/2001 dans la propriété Date
.
Désérialiser en classes et structs immuables
Newtonsoft.Json
peut désérialiser en classes et structs immuables, car il peut utiliser des constructeurs qui ont des paramètres.
Dans System.Text.Json, utilisez l’attribut [JsonConstructor] pour spécifier l’utilisation d’un constructeur paramétrable. Les enregistrements dans C# 9 sont également immuables et pris en charge en tant que cibles de désérialisation. Pour plus d’informations, consultez Types et enregistrements immuables.
Propriétés requises
Dans Newtonsoft.Json
, vous spécifiez qu’une propriété est requise en définissant Required
sur l’attribut [JsonProperty]
. Newtonsoft.Json
lève une exception si aucune valeur n’est reçue dans le JSON pour une propriété marquée comme obligatoire.
À partir de .NET 7, vous pouvez utiliser le modificateur C# required
ou l’attribut JsonRequiredAttribute sur une propriété requise. System.Text.Json lève une exception si la charge utile JSON ne contient pas de valeur pour la propriété marquée. Pour plus d’informations, consultez Propriétés requises.
System.Text.Json ne lève pas d’exception si aucune valeur n’est reçue pour l’une des propriétés du type cible. Par exemple, si vous avez une classe WeatherForecast
:
public class WeatherForecast
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
}
Le code JSON suivant est désérialisé sans erreur :
{
"TemperatureCelsius": 25,
"Summary": "Hot"
}
Pour faire échouer la désérialisation si aucune propriété Date
ne se trouve dans le JSON, choisissez l’une des options suivantes :
- Utilisez .NET 7 ou version ultérieure du package System.Text.Json et ajoutez le modificateur
required
(disponible à partir de C# 11) ou l’attribut JsonRequiredAttribute à la propriété. - Implémentez un convertisseur personnalisé.
- Implémentez un rappel
OnDeserialized
(.NET 6 et versions ultérieures).
L’exemple de code de convertisseur suivant lève une exception si la propriété Date
n’est pas définie une fois la désérialisation terminée :
using System.Text.Json;
using System.Text.Json.Serialization;
namespace SystemTextJsonSamples
{
public class WeatherForecastRequiredPropertyConverter : JsonConverter<WeatherForecast>
{
public override WeatherForecast Read(
ref Utf8JsonReader reader,
Type type,
JsonSerializerOptions options)
{
// Don't pass in options when recursively calling Deserialize.
WeatherForecast forecast = JsonSerializer.Deserialize<WeatherForecast>(ref reader)!;
// Check for required fields set by values in JSON
return forecast!.Date == default
? throw new JsonException("Required property not received in the JSON")
: forecast;
}
public override void Write(
Utf8JsonWriter writer,
WeatherForecast forecast, JsonSerializerOptions options)
{
// Don't pass in options when recursively calling Serialize.
JsonSerializer.Serialize(writer, forecast);
}
}
}
Inscrivez ce convertisseur personnalisé en ajoutant le convertisseur à la collection JsonSerializerOptions.Converters.
Ce modèle d’appel récursif du convertisseur nécessite que vous inscriviez le convertisseur à l’aide de JsonSerializerOptions, et non d’un attribut. Si vous inscrivez le convertisseur à l’aide d’un attribut, le convertisseur personnalisé s’appelle de manière récursive. Le résultat est une boucle infinie qui se termine par une exception de dépassement de capacité de la pile.
Lorsque vous inscrivez le convertisseur à l’aide de l’objet options, évitez une boucle infinie en ne transmettant pas l’objet options lors de l’appel récursif à Serialize ou Deserialize. L’objet options contient la collection Converters. Si vous le transmettez à Serialize
ou Deserialize
, le convertisseur personnalisé s’appelle lui-même, en faisant une boucle infinie qui entraîne une exception de dépassement de capacité de la pile. Si les options par défaut ne sont pas réalisables, créez une instance des options avec les paramètres dont vous avez besoin. Cette approche sera lente, car chaque nouvelle instance est mise en cache indépendamment.
Il existe un autre modèle qui peut utiliser l’inscription de JsonConverterAttribute
sur la classe à convertir. Dans cette approche, le code du convertisseur appelle Serialize
ou Deserialize
sur une classe qui dérive de la classe à convertir. La classe dérivée n’a pas de JsonConverterAttribute
appliqué. Dans l’exemple suivant de cette alternative :
WeatherForecastWithRequiredPropertyConverterAttribute
est la classe à désérialiser et à laquelle leJsonConverterAttribute
est appliqué.WeatherForecastWithoutRequiredPropertyConverterAttribute
est la classe dérivée qui n’a pas l’attribut de convertisseur.- Le code du convertisseur appelle
Serialize
etDeserialize
surWeatherForecastWithoutRequiredPropertyConverterAttribute
pour éviter une boucle infinie. Cette approche de la sérialisation entraîne un coût de performances en raison de l’ajout d’une instanciation d’objet et d’une copie des valeurs de propriété.
Voici les types WeatherForecast*
:
[JsonConverter(typeof(WeatherForecastRequiredPropertyConverterForAttributeRegistration))]
public class WeatherForecastWithRequiredPropertyConverterAttribute
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
}
public class WeatherForecastWithoutRequiredPropertyConverterAttribute :
WeatherForecastWithRequiredPropertyConverterAttribute
{
}
Et voici le convertisseur :
using System.Text.Json;
using System.Text.Json.Serialization;
namespace SystemTextJsonSamples
{
public class WeatherForecastRequiredPropertyConverterForAttributeRegistration :
JsonConverter<WeatherForecastWithRequiredPropertyConverterAttribute>
{
public override WeatherForecastWithRequiredPropertyConverterAttribute Read(
ref Utf8JsonReader reader,
Type type,
JsonSerializerOptions options)
{
// OK to pass in options when recursively calling Deserialize.
WeatherForecastWithRequiredPropertyConverterAttribute forecast =
JsonSerializer.Deserialize<WeatherForecastWithoutRequiredPropertyConverterAttribute>(
ref reader,
options)!;
// Check for required fields set by values in JSON.
return forecast!.Date == default
? throw new JsonException("Required property not received in the JSON")
: forecast;
}
public override void Write(
Utf8JsonWriter writer,
WeatherForecastWithRequiredPropertyConverterAttribute forecast,
JsonSerializerOptions options)
{
var weatherForecastWithoutConverterAttributeOnClass =
new WeatherForecastWithoutRequiredPropertyConverterAttribute
{
Date = forecast.Date,
TemperatureCelsius = forecast.TemperatureCelsius,
Summary = forecast.Summary
};
// OK to pass in options when recursively calling Serialize.
JsonSerializer.Serialize(
writer,
weatherForecastWithoutConverterAttributeOnClass,
options);
}
}
}
Le convertisseur de propriétés requis nécessite une logique supplémentaire si vous devez gérer des attributs comme [JsonIgnore] ou différentes options, comme des encodeurs personnalisés. En outre, l’exemple de code ne gère pas les propriétés pour lesquelles une valeur par défaut est définie dans le constructeur. Et cette approche ne fait pas la différence entre les scénarios suivants :
- Une propriété est manquante dans le JSON.
- Une propriété pour un type non nullable est présente dans le JSON, mais la valeur est la valeur par défaut pour le type, par exemple zéro pour un
int
. - Une propriété pour un type valeur nullable est présente dans le JSON, mais la valeur est null.
Notes
Si vous utilisez System.Text.Json à partir d’un contrôleur ASP.NET Core, vous pourrez peut-être utiliser un attribut [Required]
sur les propriétés de la classe de modèle au lieu d’implémenter un convertisseur System.Text.Json.
Spécifier le format de date
Newtonsoft.Json
offre plusieurs façons de contrôler la façon dont les propriétés des types DateTime
et DateTimeOffset
sont sérialisées et désérialisées :
- Le paramètre
DateTimeZoneHandling
peut être utilisé pour sérialiser toutes les valeurs deDateTime
sous forme de dates UTC. - Le paramètre
DateFormatString
et les convertisseursDateTime
peuvent être utilisés pour personnaliser le format des chaînes de date.
System.Text.Json prend en charge ISO 8601-1:2019, y compris le profil RFC 3339. Ce format est largement adopté, sans ambiguïté, et fait des allers-retours précis. Pour utiliser un autre format, créez un convertisseur personnalisé. Par exemple, les convertisseurs suivants sérialisent et désérialisent du JSON qui utilise le format d’époque Unix avec ou sans décalage de fuseau horaire (des valeurs comme /Date(1590863400000-0700)/
ou /Date(1590863400000)/
) :
sealed class UnixEpochDateTimeOffsetConverter : JsonConverter<DateTimeOffset>
{
static readonly DateTimeOffset s_epoch = new(1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
static readonly Regex s_regex = new("^/Date\\(([+-]*\\d+)([+-])(\\d{2})(\\d{2})\\)/$", RegexOptions.CultureInvariant);
public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
string formatted = reader.GetString()!;
Match match = s_regex.Match(formatted);
if (
!match.Success
|| !long.TryParse(match.Groups[1].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out long unixTime)
|| !int.TryParse(match.Groups[3].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out int hours)
|| !int.TryParse(match.Groups[4].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out int minutes))
{
throw new JsonException();
}
int sign = match.Groups[2].Value[0] == '+' ? 1 : -1;
TimeSpan utcOffset = new(hours * sign, minutes * sign, 0);
return s_epoch.AddMilliseconds(unixTime).ToOffset(utcOffset);
}
public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options)
{
long unixTime = Convert.ToInt64((value - s_epoch).TotalMilliseconds);
TimeSpan utcOffset = value.Offset;
string formatted = string.Create(CultureInfo.InvariantCulture, $"/Date({unixTime}{(utcOffset >= TimeSpan.Zero ? "+" : "-")}{utcOffset:hhmm})/");
writer.WriteStringValue(formatted);
}
}
sealed class UnixEpochDateTimeConverter : JsonConverter<DateTime>
{
static readonly DateTime s_epoch = new(1970, 1, 1, 0, 0, 0);
static readonly Regex s_regex = new("^/Date\\(([+-]*\\d+)\\)/$", RegexOptions.CultureInvariant);
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
string formatted = reader.GetString()!;
Match match = s_regex.Match(formatted);
if (
!match.Success
|| !long.TryParse(match.Groups[1].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out long unixTime))
{
throw new JsonException();
}
return s_epoch.AddMilliseconds(unixTime);
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
long unixTime = Convert.ToInt64((value - s_epoch).TotalMilliseconds);
string formatted = string.Create(CultureInfo.InvariantCulture, $"/Date({unixTime})/");
writer.WriteStringValue(formatted);
}
}
Pour plus d’informations, consultez Prise en charge de DateTime et DateTimeOffset dans System.Text.Json.
Rappels
Newtonsoft.Json
vous permet d’exécuter du code personnalisé à plusieurs points du processus de sérialisation ou de désérialisation :
- OnDeserializing (lorsque vous commencez à désérialiser un objet)
- OnDeserialized (lorsque vous avez terminé la désérialisation d’un objet)
- OnSerializing (lorsque vous commencez à sérialiser un objet)
- OnSerialized (lorsque vous avez terminé de sérialiser un objet)
System.Text.Json expose les mêmes notifications pendant la sérialisation et la désérialisation. Pour les utiliser, implémentez une ou plusieurs des interfaces suivantes à partir de l’espace de noms System.Text.Json.Serialization :
Voici un exemple qui recherche une propriété null et écrit des messages au début et à la fin de la sérialisation et de la désérialisation :
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Callbacks
{
public class WeatherForecast :
IJsonOnDeserializing, IJsonOnDeserialized,
IJsonOnSerializing, IJsonOnSerialized
{
public DateTime Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
void IJsonOnDeserializing.OnDeserializing() => Console.WriteLine("\nBegin deserializing");
void IJsonOnDeserialized.OnDeserialized()
{
Validate();
Console.WriteLine("Finished deserializing");
}
void IJsonOnSerializing.OnSerializing()
{
Console.WriteLine("Begin serializing");
Validate();
}
void IJsonOnSerialized.OnSerialized() => Console.WriteLine("Finished serializing");
private void Validate()
{
if (Summary is null)
{
Console.WriteLine("The 'Summary' property is 'null'.");
}
}
}
public class Program
{
public static void Main()
{
var weatherForecast = new WeatherForecast
{
Date = DateTime.Parse("2019-08-01"),
TemperatureCelsius = 25,
};
string jsonString = JsonSerializer.Serialize(weatherForecast);
Console.WriteLine(jsonString);
weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(jsonString);
Console.WriteLine($"Date={weatherForecast?.Date}");
Console.WriteLine($"TemperatureCelsius={weatherForecast?.TemperatureCelsius}");
Console.WriteLine($"Summary={weatherForecast?.Summary}");
}
}
}
// output:
//Begin serializing
//The 'Summary' property is 'null'.
//Finished serializing
//{"Date":"2019-08-01T00:00:00","TemperatureCelsius":25,"Summary":null}
//Begin deserializing
//The 'Summary' property is 'null'.
//Finished deserializing
//Date=8/1/2019 12:00:00 AM
//TemperatureCelsius = 25
//Summary=
Le code OnDeserializing
n’a pas accès à la nouvelle instance d’OCT. Pour manipuler la nouvelle instance d’OCT au début de la désérialisation, placez ce code dans le constructeur de l’OCT.
Setters et getters de propriétés non publiques
Newtonsoft.Json
peut utiliser des setters et getters de propriétés privées et internes via l’attribut JsonProperty
.
System.Text.Json prend en charge les setters et getters de propriétés privées et internes via l’attribut [JsonInclude]. Pour obtenir un exemple de code, consultez Accesseurs de propriétés non publiques.
Remplir des objets existants
La méthode JsonConvert.PopulateObject
dans Newtonsoft.Json
désérialise un document JSON sur une instance existante d’une classe au lieu de créer une nouvelle instance. System.Text.Json crée toujours une instance du type cible à l’aide du constructeur public sans paramètre par défaut. Les convertisseurs personnalisés peuvent désérialiser vers une instance existante.
Réutiliser plutôt que remplacer les propriétés
À compter de .NET 8, System.Text.Json prend en charge la réutilisation des propriétés initialisées plutôt que de les remplacer. Il existe des différences de comportement, que vous pouvez lire dans la proposition d’API.
Pour plus d’informations, consultez Remplir les propriétés initialisées.
Le paramètre ObjectCreationHandling
dans Newtonsoft.Json
vous permet de spécifier que les objets dans les propriétés doivent être réutilisés plutôt que remplacés lors de la désérialisation. System.Text.Json remplace toujours les objets dans les propriétés. Les convertisseurs personnalisés peuvent fournir cette fonctionnalité, ou vous pouvez effectuer une mise à niveau vers .NET 8 qui fournit des fonctionnalités de remplissage.
Remplir les propriétés sans aucun setter
À compter de .NET 8, System.Text.Json prend en charge le remplissage des propriétés, notamment celles qui n’ont pas de setter. Pour plus d’informations, consultez Remplir les propriétés initialisées.
Pendant la désérialisation, Newtonsoft.Json
ajoute des objets à une collection même si la propriété n’a pas de setter. System.Text.Json ignore les propriétés qui n’ont pas de setters. Les convertisseurs personnalisés peuvent fournir cette fonctionnalité, ou vous pouvez effectuer une mise à niveau vers .NET 8 qui peut remplir les propriétés en lecture seule.
Stratégie d’attribution de noms avec tirets
System.Text.Json inclut une stratégie intégrée d’affectation de noms avec des tirets. Toutefois, il existe des différences de comportement avec Newtonsoft.Json
pour certaines entrées. Le tableau suivant présente certaines de ces différences lors de la conversion d’entrée à l’aide de la stratégie JsonNamingPolicy.SnakeCaseLower.
Entrée | Résultat Newtonsoft.Json | Résultat System.Text.Json |
---|---|---|
« AB1 » | « a_b1 » | « ab1 » |
« SHA512Managed » | « sh_a512_managed » | « sha512_managed » |
« abc123DEF456 » | « abc123_de_f456 » | « abc123_def456 » |
« KEBAB-CASE » | « keba_b-_case » | « kebab-case » |
La seule stratégie intégrée d’attribution de noms de propriété dans System.Text.Json est la casse mixte. Newtonsoft.Json
peut convertir des noms de propriétés en noms à tirets. Une stratégie d’affectation de noms personnalisée peut fournir cette fonctionnalité. Sinon, effectuez une mise à niveau vers .NET 8 ou version ultérieure, qui inclut des stratégies intégrées d’affectation de noms avec des tirets.
Attributs System.Runtime.Serialization
Les attributs System.Runtime.Serialization comme DataContractAttribute, DataMemberAttribute et IgnoreDataMemberAttribute vous permettent de définir un contrat de données. Un contrat de données est un accord en bonne et due forme entre un service et un client qui décrit de manière abstraite les données à échanger. Le contrat de données définit précisément les propriétés sérialisées pour l’échange.
System.Text.Json n’a pas de prise en charge intégrée pour ces attributs. Toutefois, à partir de .NET 7, vous pouvez utiliser un programme de résolution de type personnalisé pour ajouter cette prise en charge. Pour obtenir un exemple, consultez ZCS.DataContractResolver.
Nombres octaux
Newtonsoft.Json
traite les nombres avec un zéro en tête en tant que nombres octaux. System.Text.Json n’autorise pas les zéros principaux, car la spécification RFC 8259 ne les autorise pas.
Gérer les membres manquants
Pendant la désérialisation, si le JSON inclut des propriétés manquantes dans le type cible, Newtonsoft.Json
peut être configuré pour lever des exceptions. System.Text.Json ignore par défaut les propriétés supplémentaires dans le JSON, sauf lorsque vous utilisez l’attribut [JsonExtensionData].
Dans .NET 8 et versions ultérieures, vous pouvez définir votre préférence pour ignorer ou interdire les propriétés JSON non mappées en tirant parti de l’un des moyens suivants :
- Appliquez l’attribut JsonUnmappedMemberHandlingAttribute au type vers lequel vous désérialisez.
- Pour définir votre préférence globalement, définissez la propriété JsonSerializerOptions.UnmappedMemberHandling. Ou, pour la génération de source, définissez la propriété JsonSourceGenerationOptionsAttribute.UnmappedMemberHandling et appliquez l’attribut à votre classe JsonSerializerContext.
- Personnalisez la propriété JsonTypeInfo.UnmappedMemberHandling.
JsonObjectAttribute
Newtonsoft.Json
a un attribut (JsonObjectAttribute
) qui peut être appliqué au niveau du type pour contrôler les membres sérialisés, la façon dont les valeurs null
sont gérées et si tous les membres sont requis. System.Text.Json n’a aucun attribut équivalent pouvant être appliqué à un type. Pour certains comportements, tels que la gestion des valeurs null
, vous pouvez configurer le même comportement sur le JsonSerializerOptions global ou individuellement pour chaque propriété.
Prenons l’exemple suivant qui utilise Newtonsoft.Json.JsonObjectAttribute
pour indiquer que toutes les propriétés null
doivent être ignorées :
[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)]
public class Person { ... }
Dans System.Text.Json, vous pouvez définir le comportement pour tous les types et propriétés :
JsonSerializerOptions options = new()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
string json = JsonSerializer.Serialize<Person>(person, options);
Vous pouvez également définir le comportement séparément sur chaque propriété :
public class Person
{
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Name { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public int? Age { get; set; }
}
Considérez ensuite l’exemple suivant qui utilise Newtonsoft.Json.JsonObjectAttribute
pour spécifier que toutes les propriétés de membre doivent se trouver dans le fichier JSON :
[JsonObject(ItemRequired = Required.Always)]
public class Person { ... }
Vous pouvez obtenir le même comportement dans System.Text.Json en ajoutant le modificateur C# required
ou le JsonRequiredAttribute à chaque propriété. Pour plus d’informations, consultez Propriétés requises.
public class Person
{
[JsonRequired]
public string? Name { get; set; }
public required int? Age { get; set; }
}
TraceWriter
Newtonsoft.Json
vous permet de déboguer à l’aide d’un TraceWriter
pour afficher les journaux générés par la sérialisation ou la désérialisation. System.Text.Json ne fait pas de journalisation.
JsonDocument et JsonElement comparés à JToken (comme JObject, JArray)
System.Text.Json.JsonDocument permet d’analyser et de créer un modèle DOM (Document Object Model) en lecture seule à partir de charges utiles JSON existantes. Le DOM fournit un accès aléatoire aux données dans une charge utile JSON. Les éléments JSON qui composent la charge utile sont accessibles via le type JsonElement. Le type JsonElement
fournit des API pour convertir du texte JSON en types .NET courants. JsonDocument
expose une propriété RootElement.
À partir de .NET 6, vous pouvez analyser et générer un DOM mutable à partir de charges utiles JSON existantes à l’aide du type JsonNode et d’autres types dans l’espace de noms System.Text.Json.Nodes. Pour plus d’informations, voir Utiliser JsonNode
.
JsonDocument est IDisposable
JsonDocument
génère une vue en mémoire des données dans une mémoire tampon mise en pool. Par conséquent, contrairement à JObject
ou JArray
à partir de Newtonsoft.Json
, le type JsonDocument
implémente IDisposable
et doit être utilisé à l’intérieur d’un bloc using. Pour plus d’informations, consultez JsonDocument est IDisposable.
JsonDocument est en lecture seule
Le DOM System.Text.Json ne peut pas ajouter, supprimer ou modifier des éléments JSON. Il est conçu de cette façon pour les performances et pour réduire les allocations pour l’analyse des tailles de charge utile JSON courantes (c’est-à-dire, < 1 Mo).
JsonElement est un struct d’union
JsonDocument
expose le RootElement
en tant que propriété de type JsonElement, qui est un type struct d’union qui englobe n’importe quel élément JSON. Newtonsoft.Json
utilise des types hiérarchiques dédiés comme JObject
, JArray
, JToken
, et ainsi de suite. JsonElement
est ce que vous pouvez rechercher et énumérer, et vous pouvez utiliser JsonElement
pour matérialiser des éléments JSON en types .NET.
À partir de .NET 6, vous pouvez utiliser le type JsonNode et les types dans l’espace de noms System.Text.Json.Nodes qui correspondent à JObject
, JArray
et JToken
. Pour plus d’informations, voir Utiliser JsonNode
.
Comment rechercher des sous-éléments dans JsonDocument et JsonElement
Les recherches de jetons JSON à l’aide de JObject
ou JArray
à partir de Newtonsoft.Json
ont tendance à être relativement rapides, car il s’agit de recherches dans un dictionnaire. Par comparaison, les recherches sur JsonElement
nécessitent une recherche séquentielle des propriétés et sont donc relativement lentes (par exemple lors de l’utilisation de TryGetProperty
). System.Text.Json est conçu pour réduire le temps d’analyse initial plutôt que le temps de recherche. Pour plus d’informations, consultez Comment rechercher des sous-éléments dans JsonDocument et JsonElement.
Utf8JsonReader vs. JsonTextReader
System.Text.Json.Utf8JsonReader est un lecteur hautes performances et à faible allocation de type forward-only pour le texte JSON codé au format UTF-8 et lu à partir d’un ReadOnlySpan<byte> ou ReadOnlySequence<byte>. Utf8JsonReader
est un type de bas niveau, permettant de générer des analyseurs et des désérialiseurs personnalisés.
Utf8JsonReader est un struct de référence
La JsonTextReader
dans Newtonsoft.Json
est une classe. Le type Utf8JsonReader
diffère en cela qu’il s’agit d’un struct de référence. Pour plus d’informations, consultez Limitations ref struct pour Utf8JsonReader.
Lire des valeurs null dans des types de valeurs pouvant être null
Newtonsoft.Json
fournit des API qui retournent Nullable<T>, comme ReadAsBoolean
, qui gère un Null
TokenType
pour vous en retournant un bool?
. Les API intégrées System.Text.Json
retournent uniquement des types de valeurs non nullables. Pour plus d’informations, consultez Lire des valeurs null dans des types de valeurs nullables.
Multi-cible pour la lecture de JSON
Si vous devez continuer à utiliser Newtonsoft.Json
pour certaines infrastructures cibles, vous pouvez utiliser plusieurs cibles et avoir deux implémentations. Toutefois, cela n’est pas anodin et nécessiterait des #ifdefs
et une duplication de la source. Une façon de partager autant de code que possible consiste à créer un wrapper ref struct
autour de Utf8JsonReader et Newtonsoft.Json.JsonTextReader
. Ce wrapper unifierait la surface publique tout en isolant les différences de comportement. Cela vous permet d’isoler les modifications principalement apportées à la construction du type, ainsi que de transmettre le nouveau type par référence. Voici le modèle que la bibliothèque Microsoft.Extensions.DependencyModel suit :
Utf8JsonWriter vs. JsonTextWriter
System.Text.Json.Utf8JsonWriter fournit un moyen d’écrire du texte JSON encodé en UTF-8 à partir de types .NET courants, comme String
, Int32
, et DateTime
. L’enregistreur est un type de bas niveau, permettant de générer des sérialiseurs personnalisés.
Écrire des valeurs brutes
Newtonsoft.Json
a une méthode WriteRawValue
qui écrit json brut où une valeur est attendue. System.Text.Json a un équivalent direct : Utf8JsonWriter.WriteRawValue. Pour plus d’informations, consultez Écriture de JSON brut.
Personnaliser le format JSON
JsonTextWriter
inclut les paramètres suivants, pour lesquels Utf8JsonWriter n’a pas d’équivalent :
- QuoteChar : spécifie le caractère à utiliser pour entourer les valeurs de chaîne.
Utf8JsonWriter
utilise toujours des guillemets doubles. - QuoteName : spécifie s’il faut ou non entourer les noms de propriétés de guillemets.
Utf8JsonWriter
les entoure toujours de guillemets.
À compter de .NET 9, vous pouvez personnaliser le caractère et la taille de retrait pour Utf8JsonWriter, en utilisation des options exposées par le struct JsonWriterOptions :
JsonTextWriter
inclut les paramètres suivants, pour lesquels Utf8JsonWriter
n’a pas d’équivalent :
- Indentation : spécifie le nombre de caractères de la mise en retrait.
Utf8JsonWriter
met toujours en retrait de 2 caractères. - IndentChar : spécifie le caractère à utiliser pour la mise en retrait.
Utf8JsonWriter
utilise toujours des espaces blancs. - QuoteChar : spécifie le caractère à utiliser pour entourer les valeurs de chaîne.
Utf8JsonWriter
utilise toujours des guillemets doubles. - QuoteName : spécifie s’il faut ou non entourer les noms de propriétés de guillemets.
Utf8JsonWriter
les entoure toujours de guillemets.
Il n’existe aucune solution de contournement qui vous permettrait de personnaliser le JSON généré par Utf8JsonWriter
de ces manières.
Écrire des valeurs d’intervalle de temps, d’URI ou de char
JsonTextWriter
fournit des méthodes WriteValue
pour les valeurs TimeSpan, Uri et char. Utf8JsonWriter
n’a pas de méthodes équivalentes. Au lieu de cela, formatez ces valeurs en chaînes (en appelant ToString()
, par exemple), puis appelez WriteStringValue.
Multi-cible pour l’écriture de JSON
Si vous devez continuer à utiliser Newtonsoft.Json
pour certaines infrastructures cibles, vous pouvez utiliser plusieurs cibles et avoir deux implémentations. Toutefois, cela n’est pas anodin et nécessiterait des #ifdefs
et une duplication de la source. Une façon de partager autant de code que possible consiste à créer un wrapper autour de Utf8JsonWriter et Newtonsoft.Json.JsonTextWriter
. Ce wrapper unifierait la surface publique tout en isolant les différences de comportement. Cela vous permet d’isoler les modifications principalement apportées à la construction du type. La bibliothèque Microsoft.Extensions.DependencyModel suit :
TypeNameHandling.All non pris en charge
La décision d’exclure une fonctionnalité équivalente de TypeNameHandling.All
dans System.Text.Json
était intentionnelle. Autoriser une charge utile JSON à spécifier ses propres informations de type est une source courante de vulnérabilités dans les applications web. En particulier, la configuration de Newtonsoft.Json
avec TypeNameHandling.All
permet au client distant d’incorporer une application exécutable entière dans la charge utile JSON elle-même, de sorte que pendant la désérialisation, l’application web extrait et exécute le code incorporé. Pour plus d’informations, consultez le PowerPoint Attaques JSON du vendredi 13 et Détails des attaques JSON du vendredi 13.
Requêtes de chemin JSON non prises en charge
Le DOM JsonDocument
ne prend pas en charge l’interrogation à l’aide du chemin JSON.
Dans un DOM JsonNode, chaque instance de JsonNode
a une méthode GetPath
qui retourne un chemin d’accès à ce nœud. Toutefois, il n’existe aucune API intégrée pour gérer les requêtes basées sur des chaînes de requête de chemin JSON.
Pour plus d’informations, consultez le problème GitHub dotnet/runtime #31068.
Certaines limites ne sont pas configurables
System.Text.Json définit des limites qui ne peuvent pas être modifiées pour certaines valeurs, comme la taille maximale du jeton en caractères (166 Mo) et en base 64 (125 Mo). Pour plus d’informations, consultez JsonConstants
dans le code source et le problème GitHub dotnet/runtime #39953.
NaN, Infinity, -Infinity
Newtonsoft analyse les jetons de chaîne JSON NaN
, Infinity
et -Infinity
. Avec System.Text.Json, utilisez JsonNumberHandling.AllowNamedFloatingPointLiterals. Pour plus d’informations sur l’utilisation de ce paramètre, consultez Autoriser ou écrire des nombres entre guillemets.
Utiliser GitHub Copilot pour migrer
Vous pouvez obtenir de l’aide en codage de GitHub Copilot pour convertir votre code dans votre IDE.
Si vous utilisez Visual Studio 2022 version 17.8 ou une version ultérieure, vous pouvez essayer le GitHub Copilot basé sur l’IA dans Visual Studio pour aider à migrer votre code Newtonsoft.Json
pour utiliser System.Text.Json
. Soumettez votre question et le code à convertir sous forme de flux d’invite dans la fenêtre de chat Copilot, comme dans l’exemple suivant.
Remarque
GitHub Copilot est alimenté par l’IA, donc des surprises et des erreurs sont possibles. Assurez-vous de vérifier tout code ou suggestion généré. Pour plus d’informations sur l’utilisation générale de GitHub Copilot, l’impact du produit, la supervision humaine et la confidentialité, veuillez consulter FAQ GitHub Copilot.
Exemple de prompt pour Copilot Chat
convert the following code to use System.Text.Json
Product product = new Product();
product.Name = "Apple";
product.ExpiryDate = new DateTime(2024, 08, 08);
product.Price = 3.99M;
product.Sizes = new string[] { "Small", "Medium", "Large" };
string output = JsonConvert.SerializeObject(product);
Console.WriteLine(output);
Exemple de réponse Copilot Chat
To convert the code to use System.Text.Json, you can use the JsonSerializer class. Here's the updated code:
using System;
using System.Text.Json;
public class Product
{
public string Name { get; set; }
public DateTime ExpiryDate { get; set; }
public decimal Price { get; set; }
public string[] Sizes { get; set; }
}
public class Program
{
public static void Main()
{
Product product = new Product();
product.Name = "Apple";
product.ExpiryDate = new DateTime(2024, 08, 08);
product.Price = 3.99M;
product.Sizes = new string[] { "Small", "Medium", "Large" };
string output = JsonSerializer.Serialize(product);
Console.WriteLine(output);
}
}
This code uses System.Text.Json.JsonSerializer.Serialize to convert the Product object to a JSON string.
Notez que vos résultats peuvent être différents de ceux montrés dans ces exemples de réponses. Les modèles IA sont non déterministes, ce qui signifie qu’ils peuvent renvoyer des réponses différentes lorsqu’on leur pose la même question. Cela peut être dû à un apprentissage et à une adaptation supplémentaires au fil du temps, à une variation de la langue, à des changements de contexte, tels que l’historique de votre chat, et plus encore.
Vous pouvez utiliser des fonctionnalités de chat, telles que les commandes slash, les références et les fils de discussion, pour définir l’intention et obtenir de meilleures réponses avec un contexte délimité.
Par exemple, si votre fichier de code filename
est ouvert dans l’IDE, vous pouvez référencer le fichier dans votre flux d’invite à Copilot Chat avec « convertir #filename
pour utiliser System.Text.Json
». Ou vous pouvez référencer la solution avec « convertir @workspace
pour utiliser System.Text.Json
» dans la fenêtre de chat ou dans le chat en ligne.