Guide pratique pour utiliser un modèle objet de document JSON dans System.Text.Json
Cet article montre comment utiliser un modèle DOM (Document Object Model) JSON pour l’accès aléatoire aux données dans une charge utile JSON.
Choix de DOM JSON
L’utilisation d’un DOM est une alternative à la désérialisation avec JsonSerializer :
- Lorsque vous n’avez pas de type dans lequel désérialiser.
- Lorsque le JSON que vous recevez n’a pas de schéma fixe et doit être inspecté pour savoir ce qu’il contient.
System.Text.Json
fournit deux façons de générer un DOM JSON :
JsonDocument permet de créer un DOM en lecture seule à l’aide de
Utf8JsonReader
. Les éléments JSON qui composent la charge utile sont accessibles via le type JsonElement. Le typeJsonElement
fournit le tableau et les énumérateurs d’objets JSON, ainsi que des API pour convertir le texte JSON en types .NET courants.JsonDocument
expose une propriété RootElement. Pour plus d’informations, consultez Utilisation de JsonDocument, plus loin dans cet article.JsonNode et les classes qui en dérivent dans l’espace de noms System.Text.Json.Nodes permettent de créer un DOM mutable. Les éléments JSON qui composent la charge utile sont accessibles via les types JsonNode, JsonObject, JsonArray, JsonValue et JsonElement. Pour plus d’informations, consultez Utiliser
JsonNode
plus loin dans cet article.
Tenez compte des facteurs suivants lors du choix entre JsonDocument
et JsonNode
:
- Le DOM
JsonNode
peut être modifié après sa création. Le DOMJsonDocument
est immuable. - Le DOM
JsonDocument
offre un accès plus rapide à ses données.
Utilisez JsonNode
.
L’exemple suivant montre comment utiliser JsonNode et les autres types de l’espace de noms System.Text.Json.Nodes pour :
- Créer un DOM à partir d’une chaîne JSON
- Écrire du JSON à partir d’un DOM.
- Obtenir une valeur, un objet ou un tableau à partir d’un DOM.
using System.Text.Json;
using System.Text.Json.Nodes;
namespace JsonNodeFromStringExample;
public class Program
{
public static void Main()
{
string jsonString = """
{
"Date": "2019-08-01T00:00:00",
"Temperature": 25,
"Summary": "Hot",
"DatesAvailable": [
"2019-08-01T00:00:00",
"2019-08-02T00:00:00"
],
"TemperatureRanges": {
"Cold": {
"High": 20,
"Low": -10
},
"Hot": {
"High": 60,
"Low": 20
}
}
}
""";
// Create a JsonNode DOM from a JSON string.
JsonNode forecastNode = JsonNode.Parse(jsonString)!;
// Write JSON from a JsonNode
var options = new JsonSerializerOptions { WriteIndented = true };
Console.WriteLine(forecastNode!.ToJsonString(options));
// output:
//{
// "Date": "2019-08-01T00:00:00",
// "Temperature": 25,
// "Summary": "Hot",
// "DatesAvailable": [
// "2019-08-01T00:00:00",
// "2019-08-02T00:00:00"
// ],
// "TemperatureRanges": {
// "Cold": {
// "High": 20,
// "Low": -10
// },
// "Hot": {
// "High": 60,
// "Low": 20
// }
// }
//}
// Get value from a JsonNode.
JsonNode temperatureNode = forecastNode!["Temperature"]!;
Console.WriteLine($"Type={temperatureNode.GetType()}");
Console.WriteLine($"JSON={temperatureNode.ToJsonString()}");
//output:
//Type = System.Text.Json.Nodes.JsonValue`1[System.Text.Json.JsonElement]
//JSON = 25
// Get a typed value from a JsonNode.
int temperatureInt = (int)forecastNode!["Temperature"]!;
Console.WriteLine($"Value={temperatureInt}");
//output:
//Value=25
// Get a typed value from a JsonNode by using GetValue<T>.
temperatureInt = forecastNode!["Temperature"]!.GetValue<int>();
Console.WriteLine($"TemperatureInt={temperatureInt}");
//output:
//Value=25
// Get a JSON object from a JsonNode.
JsonNode temperatureRanges = forecastNode!["TemperatureRanges"]!;
Console.WriteLine($"Type={temperatureRanges.GetType()}");
Console.WriteLine($"JSON={temperatureRanges.ToJsonString()}");
//output:
//Type = System.Text.Json.Nodes.JsonObject
//JSON = { "Cold":{ "High":20,"Low":-10},"Hot":{ "High":60,"Low":20} }
// Get a JSON array from a JsonNode.
JsonNode datesAvailable = forecastNode!["DatesAvailable"]!;
Console.WriteLine($"Type={datesAvailable.GetType()}");
Console.WriteLine($"JSON={datesAvailable.ToJsonString()}");
//output:
//datesAvailable Type = System.Text.Json.Nodes.JsonArray
//datesAvailable JSON =["2019-08-01T00:00:00", "2019-08-02T00:00:00"]
// Get an array element value from a JsonArray.
JsonNode firstDateAvailable = datesAvailable[0]!;
Console.WriteLine($"Type={firstDateAvailable.GetType()}");
Console.WriteLine($"JSON={firstDateAvailable.ToJsonString()}");
//output:
//Type = System.Text.Json.Nodes.JsonValue`1[System.Text.Json.JsonElement]
//JSON = "2019-08-01T00:00:00"
// Get a typed value by chaining references.
int coldHighTemperature = (int)forecastNode["TemperatureRanges"]!["Cold"]!["High"]!;
Console.WriteLine($"TemperatureRanges.Cold.High={coldHighTemperature}");
//output:
//TemperatureRanges.Cold.High = 20
// Parse a JSON array
var datesNode = JsonNode.Parse(@"[""2019-08-01T00:00:00"",""2019-08-02T00:00:00""]");
JsonNode firstDate = datesNode![0]!.GetValue<DateTime>();
Console.WriteLine($"firstDate={ firstDate}");
//output:
//firstDate = "2019-08-01T00:00:00"
}
}
Créer un DOM JsonNode avec des initialiseurs d’objet et apporter des modifications
L’exemple suivant montre comment :
- Créer un DOM à l’aide d’initialiseurs d’objets.
- Apporter des modifications à un DOM.
using System.Text.Json;
using System.Text.Json.Nodes;
namespace JsonNodeFromObjectExample;
public class Program
{
public static void Main()
{
// Create a new JsonObject using object initializers.
var forecastObject = new JsonObject
{
["Date"] = new DateTime(2019, 8, 1),
["Temperature"] = 25,
["Summary"] = "Hot",
["DatesAvailable"] = new JsonArray(
new DateTime(2019, 8, 1), new DateTime(2019, 8, 2)),
["TemperatureRanges"] = new JsonObject
{
["Cold"] = new JsonObject
{
["High"] = 20,
["Low"] = -10
}
},
["SummaryWords"] = new JsonArray("Cool", "Windy", "Humid")
};
// Add an object.
forecastObject!["TemperatureRanges"]!["Hot"] =
new JsonObject { ["High"] = 60, ["Low"] = 20 };
// Remove a property.
forecastObject.Remove("SummaryWords");
// Change the value of a property.
forecastObject["Date"] = new DateTime(2019, 8, 3);
var options = new JsonSerializerOptions { WriteIndented = true };
Console.WriteLine(forecastObject.ToJsonString(options));
//output:
//{
// "Date": "2019-08-03T00:00:00",
// "Temperature": 25,
// "Summary": "Hot",
// "DatesAvailable": [
// "2019-08-01T00:00:00",
// "2019-08-02T00:00:00"
// ],
// "TemperatureRanges": {
// "Cold": {
// "High": 20,
// "Low": -10
// },
// "Hot": {
// "High": 60,
// "Low": 20
// }
// }
//}
}
}
Désérialiser les sous-sections d’une charge utile JSON
L’exemple suivant montre comment utiliser JsonNode pour accéder à une sous-section d’une arborescence JSON et désérialiser une valeur unique, un type personnalisé ou un tableau de cette sous-section.
using System.Text.Json;
using System.Text.Json.Nodes;
namespace JsonNodePOCOExample;
public class TemperatureRanges : Dictionary<string, HighLowTemps>
{
}
public class HighLowTemps
{
public int High { get; set; }
public int Low { get; set; }
}
public class Program
{
public static DateTime[]? DatesAvailable { get; set; }
public static void Main()
{
string jsonString = """
{
"Date": "2019-08-01T00:00:00",
"Temperature": 25,
"Summary": "Hot",
"DatesAvailable": [
"2019-08-01T00:00:00",
"2019-08-02T00:00:00"
],
"TemperatureRanges": {
"Cold": {
"High": 20,
"Low": -10
},
"Hot": {
"High": 60,
"Low": 20
}
}
}
""";
// Parse all of the JSON.
JsonNode forecastNode = JsonNode.Parse(jsonString)!;
// Get a single value
int hotHigh = forecastNode["TemperatureRanges"]!["Hot"]!["High"]!.GetValue<int>();
Console.WriteLine($"Hot.High={hotHigh}");
// output:
//Hot.High=60
// Get a subsection and deserialize it into a custom type.
JsonObject temperatureRangesObject = forecastNode!["TemperatureRanges"]!.AsObject();
using var stream = new MemoryStream();
using var writer = new Utf8JsonWriter(stream);
temperatureRangesObject.WriteTo(writer);
writer.Flush();
TemperatureRanges? temperatureRanges =
JsonSerializer.Deserialize<TemperatureRanges>(stream.ToArray());
Console.WriteLine($"Cold.Low={temperatureRanges!["Cold"].Low}, Hot.High={temperatureRanges["Hot"].High}");
// output:
//Cold.Low=-10, Hot.High=60
// Get a subsection and deserialize it into an array.
JsonArray datesAvailable = forecastNode!["DatesAvailable"]!.AsArray()!;
Console.WriteLine($"DatesAvailable[0]={datesAvailable[0]}");
// output:
//DatesAvailable[0]=8/1/2019 12:00:00 AM
}
}
Exemple de note moyenne avec JsonNode
L’exemple suivant sélectionne un tableau JSON qui contient des valeurs entières et calcule une valeur moyenne :
using System.Text.Json.Nodes;
namespace JsonNodeAverageGradeExample;
public class Program
{
public static void Main()
{
string jsonString = """
{
"Class Name": "Science",
"Teacher\u0027s Name": "Jane",
"Semester": "2019-01-01",
"Students": [
{
"Name": "John",
"Grade": 94.3
},
{
"Name": "James",
"Grade": 81.0
},
{
"Name": "Julia",
"Grade": 91.9
},
{
"Name": "Jessica",
"Grade": 72.4
},
{
"Name": "Johnathan"
}
],
"Final": true
}
""";
double sum = 0;
JsonNode document = JsonNode.Parse(jsonString)!;
JsonNode root = document.Root;
JsonArray studentsArray = root["Students"]!.AsArray();
int count = studentsArray.Count;
foreach (JsonNode? student in studentsArray)
{
if (student?["Grade"] is JsonNode gradeNode)
{
sum += (double)gradeNode;
}
else
{
sum += 70;
}
}
double average = sum / count;
Console.WriteLine($"Average grade : {average}");
}
}
// output:
//Average grade : 81.92
Le code précédent :
- Calcule une note moyenne pour les objets d’un tableau
Students
qui ont une propriétéGrade
. - Attribue une note par défaut de 70 aux étudiants qui n’ont pas de note.
- Obtient le nombre d’étudiants à partir de la propriété
Count
deJsonArray
.
JsonNode
avec JsonSerializerOptions
Vous pouvez utiliser JsonSerializer
pour sérialiser et désérialiser une instance de JsonNode
. Toutefois, si vous utilisez une surcharge qui prend JsonSerializerOptions
, l’instance options est utilisée uniquement pour obtenir des convertisseurs personnalisés. Les autres fonctionnalités de l’instance options ne sont pas utilisées. Par exemple, si vous définissez JsonSerializerOptions.DefaultIgnoreCondition sur WhenWritingNull et appelez JsonSerializer
avec une surcharge qui prend JsonSerializerOptions
, les propriétés null ne seront pas ignorées.
La même limitation s’applique aux méthodes JsonNode
qui prennent un paramètre JsonSerializerOptions
: WriteTo(Utf8JsonWriter, JsonSerializerOptions) et ToJsonString(JsonSerializerOptions). Ces API utilisent JsonSerializerOptions
uniquement pour obtenir des convertisseurs personnalisés.
L’exemple suivant illustre le résultat de l’utilisation de méthodes qui prennent un paramètre JsonSerializerOptions
et sérialisent une instance JsonNode
:
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
namespace JsonNodeWithJsonSerializerOptions;
public class Program
{
public static void Main()
{
Person person = new() { Name = "Nancy" };
// Default serialization - Address property included with null token.
// Output: {"Name":"Nancy","Address":null}
string personJsonWithNull = JsonSerializer.Serialize(person);
Console.WriteLine(personJsonWithNull);
// Serialize and ignore null properties - null Address property is omitted
// Output: {"Name":"Nancy"}
JsonSerializerOptions options = new()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
string personJsonWithoutNull = JsonSerializer.Serialize(person, options);
Console.WriteLine(personJsonWithoutNull);
// Ignore null properties doesn't work when serializing JsonNode instance
// by using JsonSerializer.
// Output: {"Name":"Nancy","Address":null}
JsonNode? personJsonNode = JsonSerializer.Deserialize<JsonNode>(personJsonWithNull);
personJsonWithNull = JsonSerializer.Serialize(personJsonNode, options);
Console.WriteLine(personJsonWithNull);
// Ignore null properties doesn't work when serializing JsonNode instance
// by using JsonNode.ToJsonString method.
// Output: {"Name":"Nancy","Address":null}
personJsonWithNull = personJsonNode!.ToJsonString(options);
Console.WriteLine(personJsonWithNull);
// Ignore null properties doesn't work when serializing JsonNode instance
// by using JsonNode.WriteTo method.
// Output: {"Name":"Nancy","Address":null}
using var stream = new MemoryStream();
using var writer = new Utf8JsonWriter(stream);
personJsonNode!.WriteTo(writer, options);
writer.Flush();
personJsonWithNull = Encoding.UTF8.GetString(stream.ToArray());
Console.WriteLine(personJsonWithNull);
}
}
public class Person
{
public string? Name { get; set; }
public string? Address { get; set; }
}
Si vous avez besoin de fonctionnalités JsonSerializerOptions
autres que des convertisseurs personnalisés, utilisez JsonSerializer
avec des cibles fortement typées (comme la classe Person
dans cet exemple) plutôt que JsonNode
.
Manipuler l’ordre des propriétés
JsonObject est l’un des éléments dans la charge utile d’un JsonNode, et il représente un objet JSON mutable. Même si le type est modélisé comme un IDictionary<string, JsonNode>
, où chaque entrée est une propriété de l’objet, il encapsule un ordre implicite des propriétés. Cependant, les API telles que Insert(Int32, String, JsonNode) et RemoveAt(Int32) modélisent effectivement le type comme un dictionnaire ordonné en vous permettant d’insérer et de supprimer des éléments à un indice spécifique. Ces API permettent des modifications des instances d’objet qui peuvent directement influencer l’ordre des propriétés.
Le code suivant montre un exemple d’ajout ou de déplacement d’une propriété spécifique au début de l’objet.
var schema = (JsonObject)JsonSerializerOptions.Default.GetJsonSchemaAsNode(typeof(MyPoco));
JsonNode? idValue;
switch (schema.IndexOf("$id"))
{
// $id property missing.
case < 0:
idValue = (JsonNode)"https://example.com/schema";
schema.Insert(0, "$id", idValue);
break;
// $id property already at the start of the object.
case 0:
break;
// $id exists but not at the start of the object.
case int index:
idValue = schema[index];
schema.RemoveAt(index);
schema.Insert(0, "$id", idValue);
break;
}
Comparer des JsonNodes
Pour comparer deux objets JsonNode
pour l’égalité, y compris leurs éléments descendants, utilisez la méthode JsonNode.DeepEquals(JsonNode, JsonNode).
Utilisez JsonDocument
.
L’exemple suivant montre comment utiliser la classe JsonDocument pour l’accès aléatoire aux données dans une chaîne JSON :
double sum = 0;
int count = 0;
using (JsonDocument document = JsonDocument.Parse(jsonString))
{
JsonElement root = document.RootElement;
JsonElement studentsElement = root.GetProperty("Students");
foreach (JsonElement student in studentsElement.EnumerateArray())
{
if (student.TryGetProperty("Grade", out JsonElement gradeElement))
{
sum += gradeElement.GetDouble();
}
else
{
sum += 70;
}
count++;
}
}
double average = sum / count;
Console.WriteLine($"Average grade : {average}");
Dim sum As Double = 0
Dim count As Integer = 0
Using document As JsonDocument = JsonDocument.Parse(jsonString)
Dim root As JsonElement = document.RootElement
Dim studentsElement As JsonElement = root.GetProperty("Students")
For Each student As JsonElement In studentsElement.EnumerateArray()
Dim gradeElement As JsonElement = Nothing
If student.TryGetProperty("Grade", gradeElement) Then
sum += gradeElement.GetDouble()
Else
sum += 70
End If
count += 1
Next
End Using
Dim average As Double = sum / count
Console.WriteLine($"Average grade : {average}")
Le code précédent :
- Suppose que le JSON à analyser se trouve dans une chaîne nommée
jsonString
. - Calcule une note moyenne pour les objets d’un tableau
Students
qui ont une propriétéGrade
. - Attribue une note par défaut de 70 aux étudiants qui n’ont pas de note.
- Crée l’instance
JsonDocument
dans une instructionusing
, carJsonDocument
implémenteIDisposable
. Une fois qu’une instanceJsonDocument
est supprimée, vous perdez également l’accès à toutes ses instancesJsonElement
. Pour conserver l’accès à une instanceJsonElement
, effectuez une copie avant la suppression de l’instance parenteJsonDocument
. Pour effectuer une copie, appelez JsonElement.Clone. Pour plus d’informations, consultez JsonDocument est IDisposable.
L’exemple de code précédent compte les étudiants en incrémentant une variable count
à chaque itération. Une alternative consiste à appeler GetArrayLength, comme illustré dans l’exemple suivant :
double sum = 0;
int count = 0;
using (JsonDocument document = JsonDocument.Parse(jsonString))
{
JsonElement root = document.RootElement;
JsonElement studentsElement = root.GetProperty("Students");
count = studentsElement.GetArrayLength();
foreach (JsonElement student in studentsElement.EnumerateArray())
{
if (student.TryGetProperty("Grade", out JsonElement gradeElement))
{
sum += gradeElement.GetDouble();
}
else
{
sum += 70;
}
}
}
double average = sum / count;
Console.WriteLine($"Average grade : {average}");
Dim sum As Double = 0
Dim count As Integer = 0
Using document As JsonDocument = JsonDocument.Parse(jsonString)
Dim root As JsonElement = document.RootElement
Dim studentsElement As JsonElement = root.GetProperty("Students")
count = studentsElement.GetArrayLength()
For Each student As JsonElement In studentsElement.EnumerateArray()
Dim gradeElement As JsonElement = Nothing
If student.TryGetProperty("Grade", gradeElement) Then
sum += gradeElement.GetDouble()
Else
sum += 70
End If
Next
End Using
Dim average As Double = sum / count
Console.WriteLine($"Average grade : {average}")
Voici un exemple du JSON que ce code traite :
{
"Class Name": "Science",
"Teacher\u0027s Name": "Jane",
"Semester": "2019-01-01",
"Students": [
{
"Name": "John",
"Grade": 94.3
},
{
"Name": "James",
"Grade": 81.0
},
{
"Name": "Julia",
"Grade": 91.9
},
{
"Name": "Jessica",
"Grade": 72.4
},
{
"Name": "Johnathan"
}
],
"Final": true
}
Pour obtenir un exemple similaire qui utilise JsonNode
au lieu de JsonDocument
, consultez Exemple de note moyenne avec JsonNode.
Comment rechercher des sous-éléments dans JsonDocument et JsonElement
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. Par conséquent, utilisez les approches suivantes pour optimiser les performances lors de la recherche dans un objet JsonDocument
:
- Utilisez les énumérateurs intégrés (EnumerateArray et EnumerateObject) plutôt que d’effectuer vos propres boucles ou indexations.
- N’effectuez pas de recherche séquentielle dans l’ensemble de
JsonDocument
via chaque propriété en utilisantRootElement
. Au lieu de cela, recherchez des objets JSON imbriqués en fonction de la structure connue des données JSON. Par exemple, les exemples de code précédents recherchent une propriétéGrade
dans les objetsStudent
en faisant une boucle dans les objetsStudent
et en obtenant la valeur deGrade
pour chacun, plutôt que de rechercher tous les objetsJsonElement
à la recherche de propriétésGrade
. L’exécution de cette dernière approche entraînerait des passages inutiles sur les mêmes données.
Comparer des JsonElements
Pour comparer deux objets JsonElement
pour l’égalité, y compris leurs éléments descendants, utilisez la méthode JsonElement.DeepEquals(JsonElement, JsonElement).
JsonElement left = JsonDocument.Parse("10e-3").RootElement;
JsonElement right = JsonDocument.Parse("0.01").RootElement;
bool equal = JsonElement.DeepEquals(left, right);
Console.WriteLine(equal); // True.
Utiliser JsonDocument
pour écrire du JSON
L’exemple suivant montre comment écrire du code JSON à partir d’un JsonDocument :
string jsonString = File.ReadAllText(inputFileName);
var writerOptions = new JsonWriterOptions
{
Indented = true
};
var documentOptions = new JsonDocumentOptions
{
CommentHandling = JsonCommentHandling.Skip
};
using FileStream fs = File.Create(outputFileName);
using var writer = new Utf8JsonWriter(fs, options: writerOptions);
using JsonDocument document = JsonDocument.Parse(jsonString, documentOptions);
JsonElement root = document.RootElement;
if (root.ValueKind == JsonValueKind.Object)
{
writer.WriteStartObject();
}
else
{
return;
}
foreach (JsonProperty property in root.EnumerateObject())
{
property.WriteTo(writer);
}
writer.WriteEndObject();
writer.Flush();
Dim jsonString As String = File.ReadAllText(inputFileName)
Dim writerOptions As JsonWriterOptions = New JsonWriterOptions With {
.Indented = True
}
Dim documentOptions As JsonDocumentOptions = New JsonDocumentOptions With {
.CommentHandling = JsonCommentHandling.Skip
}
Dim fs As FileStream = File.Create(outputFileName)
Dim writer As Utf8JsonWriter = New Utf8JsonWriter(fs, options:=writerOptions)
Dim document As JsonDocument = JsonDocument.Parse(jsonString, documentOptions)
Dim root As JsonElement = document.RootElement
If root.ValueKind = JsonValueKind.[Object] Then
writer.WriteStartObject()
Else
Return
End If
For Each [property] As JsonProperty In root.EnumerateObject()
[property].WriteTo(writer)
Next
writer.WriteEndObject()
writer.Flush()
Le code précédent :
- Lit un fichier JSON, charge les données dans un fichier
JsonDocument
et écrit un fichier JSON mis en forme (imprimé élégamment). - Utilise JsonDocumentOptions pour spécifier que les commentaires dans le JSON d’entrée sont autorisés mais ignorés.
- Une fois cela terminé, appelle Flush sur l’enregistreur. Une alternative consiste à laisser l’enregistreur se vider automatiquement lorsqu’il est supprimé.
Voici un exemple d’entrée JSON à traiter par l’exemple de code :
{"Class Name": "Science","Teacher's Name": "Jane","Semester": "2019-01-01","Students": [{"Name": "John","Grade": 94.3},{"Name": "James","Grade": 81.0},{"Name": "Julia","Grade": 91.9},{"Name": "Jessica","Grade": 72.4},{"Name": "Johnathan"}],"Final": true}
Le résultat est la sortie JSON imprimée de façon élégante suivante :
{
"Class Name": "Science",
"Teacher\u0027s Name": "Jane",
"Semester": "2019-01-01",
"Students": [
{
"Name": "John",
"Grade": 94.3
},
{
"Name": "James",
"Grade": 81.0
},
{
"Name": "Julia",
"Grade": 91.9
},
{
"Name": "Jessica",
"Grade": 72.4
},
{
"Name": "Johnathan"
}
],
"Final": true
}
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, le type JsonDocument
implémente IDisposable
et doit être utilisé à l’intérieur d’un bloc using
.
Retournez un JsonDocument
à partir de votre API uniquement si vous souhaitez transférer la propriété de la durée de vie et éliminer la responsabilité de l’appelant. Dans la plupart des scénarios, cela n’est pas nécessaire. Si l’appelant doit travailler avec l’intégralité du document JSON, retournez le Clone du RootElement, qui est un JsonElement. Si l’appelant doit travailler avec un élément particulier dans le document JSON, retournez le Clone de ce JsonElement. Si vous retournez le RootElement
ou un sous-élément directement sans effectuer de Clone
, l’appelant ne pourra pas accéder au JsonElement
retourné une fois que le JsonDocument
propriétaire est supprimé.
Voici un exemple qui vous oblige à effectuer un Clone
:
public JsonElement LookAndLoad(JsonElement source)
{
string json = File.ReadAllText(source.GetProperty("fileName").GetString());
using (JsonDocument doc = JsonDocument.Parse(json))
{
return doc.RootElement.Clone();
}
}
Le code précédent attend un JsonElement
qui contient une propriété fileName
. Il ouvre le fichier JSON et crée un JsonDocument
. La méthode part du principe que l’appelant souhaite travailler avec l’ensemble du document. Elle retourne donc le Clone
du RootElement
.
Si vous recevez un JsonElement
et que vous retournez un sous-élément, il n’est pas nécessaire de retourner un Clone
de ce sous-élément. L’appelant est chargé de maintenir en vie le JsonDocument
auquel appartient le JsonElement
passé. Par exemple :
public JsonElement ReturnFileName(JsonElement source)
{
return source.GetProperty("fileName");
}
JsonDocument
avec JsonSerializerOptions
Vous pouvez utiliser JsonSerializer
pour sérialiser et désérialiser une instance de JsonDocument
. Toutefois, l’implémentation de lecture et d’écriture d’instances JsonDocument
à l’aide de JsonSerializer
est un wrapper sur JsonDocument.ParseValue(Utf8JsonReader) et JsonDocument.WriteTo(Utf8JsonWriter). Ce wrapper ne transfère pas de JsonSerializerOptions
(fonctionnalités de sérialiseur) vers Utf8JsonReader
ou Utf8JsonWriter
. Par exemple, si vous définissez JsonSerializerOptions.DefaultIgnoreCondition sur WhenWritingNull et appelez JsonSerializer
avec une surcharge qui prend JsonSerializerOptions
, les propriétés null ne seront pas ignorées.
L’exemple suivant illustre le résultat de l’utilisation de méthodes qui prennent un paramètre JsonSerializerOptions
et sérialisent une instance de JsonDocument
:
using System.Text.Json;
using System.Text.Json.Serialization;
namespace JsonDocumentWithJsonSerializerOptions;
public class Program
{
public static void Main()
{
Person person = new() { Name = "Nancy" };
// Default serialization - Address property included with null token.
// Output: {"Name":"Nancy","Address":null}
string personJsonWithNull = JsonSerializer.Serialize(person);
Console.WriteLine(personJsonWithNull);
// Serialize and ignore null properties - null Address property is omitted
// Output: {"Name":"Nancy"}
JsonSerializerOptions options = new()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
string personJsonWithoutNull = JsonSerializer.Serialize(person, options);
Console.WriteLine(personJsonWithoutNull);
// Ignore null properties doesn't work when serializing JsonDocument instance
// by using JsonSerializer.
// Output: {"Name":"Nancy","Address":null}
JsonDocument? personJsonDocument = JsonSerializer.Deserialize<JsonDocument>(personJsonWithNull);
personJsonWithNull = JsonSerializer.Serialize(personJsonDocument, options);
Console.WriteLine(personJsonWithNull);
}
}
public class Person
{
public string? Name { get; set; }
public string? Address { get; set; }
}
Si vous avez besoin de fonctionnalités JsonSerializerOptions
, utilisez JsonSerializer
avec des cibles fortement typées (comme la classe Person
dans cet exemple) plutôt que JsonDocument
.