Como usar um modelo de objeto de documento do JSON em System.Text.Json
Este artigo mostra como usar um DOM (modelo de objeto de documento) do JSON para acesso aleatório a dados em um conteúdo do JSON.
Opções de DOM JSON
Trabalhar com um DOM é uma alternativa à desserialização com JsonSerializer quando:
- Você não tem um tipo para desserializar.
- O JSON que você recebe não tem um esquema fixo e deve ser inspecionado para saber o que ele contém.
System.Text.Json
fornece duas maneiras de criar um DOM JSON:
JsonDocument fornece a capacidade de criar um DOM somente leitura usando
Utf8JsonReader
. Os elementos JSON que compõem o conteúdo podem ser acessados pelo tipo JsonElement. O tipoJsonElement
fornece os enumeradores de objeto e de matriz JSON junto com as APIs para converter o texto JSON em tipos .NET comuns.JsonDocument
expõe uma propriedade RootElement. Para obter mais informações, consulte Usar JsonDocument posteriormente neste artigo.JsonNode e as classes que derivam dele no namespace System.Text.Json.Nodes fornecem a capacidade de criar um DOM mutável. Os elementos JSON que compõem o conteúdo podem ser acessados por meio dos tipos JsonNode, JsonObject, JsonArray, JsonValue e JsonElement. Para obter mais informações, consulte Usar
JsonNode
posteriormente neste artigo.
Considere os seguintes fatores ao escolher entre JsonDocument
e JsonNode
:
- O DOM
JsonNode
pode ser alterado depois de criado. O DOMJsonDocument
é imutável. - O DOM
JsonDocument
fornece acesso mais rápido aos seus dados.
Use JsonNode
.
O exemplo a seguir mostra como usar JsonNode e os outros tipos no namespace System.Text.Json.Nodes para:
- Criar um DOM com base em uma cadeia de caracteres JSON
- Escreva JSON de um DOM.
- Obtenha um valor, objeto ou matriz de um 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"
}
}
Criar um DOM JsonNode com inicializadores de objeto e fazer alterações
O exemplo a seguir mostra como:
- Crie um DOM usando inicializadores de objeto.
- Faça alterações em um 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
// }
// }
//}
}
}
Desserializar subseções de um conteúdo JSON
O exemplo a seguir mostra como usar jsonNode para navegar até uma subseção de uma árvore JSON e desserializar um único valor, um tipo personalizado ou uma matriz dessa subseção.
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
}
}
Exemplo de nota média JsonNode
O exemplo a seguir seleciona uma matriz JSON que tem valores inteiros e calcula um valor médio:
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
O código anterior:
- Calcula uma nota média para objetos em uma matriz
Students
que tem uma propriedadeGrade
. - Atribui uma nota padrão de 70 para alunos sem nota.
- Obtém o número de alunos da propriedade
Count
deJsonArray
.
JsonNode
com JsonSerializerOptions
Você pode usar JsonSerializer
para serializar e desserializar uma instância de JsonNode
. No entanto, se você usar uma sobrecarga que leva JsonSerializerOptions
, a instância de opções só será usada para obter conversores personalizados. Outros recursos da instância de opções não são usados. Por exemplo, se você definir JsonSerializerOptions.DefaultIgnoreCondition como WhenWritingNull e chamar JsonSerializer
com uma sobrecarga que leva JsonSerializerOptions
, as propriedades nulas não serão ignoradas.
A mesma limitação se aplica aos métodos JsonNode
que usam um parâmetro JsonSerializerOptions
: WriteTo(Utf8JsonWriter, JsonSerializerOptions) e ToJsonString(JsonSerializerOptions). Essas APIs usam JsonSerializerOptions
apenas para obter conversores personalizados.
O exemplo a seguir ilustra o resultado do uso de métodos que usam um parâmetro JsonSerializerOptions
e serializam uma instância 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; }
}
Se você precisar de recursos JsonSerializerOptions
diferentes de conversores personalizados, use JsonSerializer
com destinos fortemente tipados (como a classe Person
neste exemplo) em vez de JsonNode
.
Manipular ordem de propriedade
JsonObject é um dos elementos no payload de um JsonNode, e representa um objeto JSON mutável. Mesmo que o tipo seja modelado como um IDictionary<string, JsonNode>
, em que cada entrada é uma propriedade do objeto, ele encapsula uma ordem de propriedade implícita. No entanto, APIs como Insert(Int32, String, JsonNode) e RemoveAt(Int32) modelam efetivamente o tipo como um dicionário ordenado, permitindo que você insira e remova itens em um índice específico. Essas APIs permitem modificações em instâncias de objeto que podem influenciar diretamente a ordem das propriedades.
O código a seguir mostra um exemplo de adição ou movimentação de uma propriedade específica para o início do objeto.
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;
}
Comparar JsonNodes
Para comparar dois objetos JsonNode
quanto à igualdade, incluindo seus elementos descendentes, use o método JsonNode.DeepEquals(JsonNode, JsonNode).
Use JsonDocument
.
O exemplo a seguir mostra como usar a classe JsonDocument para acesso aleatório a dados em uma cadeia de caracteres 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}")
O código anterior:
- Pressupõe que o JSON a ser analisado esteja em uma cadeia de caracteres chamada
jsonString
. - Calcula uma nota média para objetos em uma matriz
Students
que tem uma propriedadeGrade
. - Atribui uma nota padrão de 70 para alunos sem nota.
- Cria a instância
JsonDocument
em umausing
instrução porqueJsonDocument
implementaIDisposable
. Depois que uma instânciaJsonDocument
é descartada, você perde o acesso a todas as suas instânciasJsonElement
também. Para manter o acesso a uma instânciaJsonElement
, faça uma cópia dela antes que a instância paiJsonDocument
seja descartada. Para fazer uma cópia, chame JsonElement.Clone. Para obter mais informações, consulte JsonDocument é IDisposable.
O código de exemplo anterior conta os alunos incrementando uma variável count
com cada iteração. Uma alternativa é chamar GetArrayLength, conforme mostrado no exemplo a seguir:
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}")
Aqui está um exemplo do JSON que este código processa:
{
"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
}
Para um exemplo semelhante que usa JsonNode
em vez de JsonDocument
, consulte Exemplo de nota média de JsonNode.
Como pesquisar um JsonDocument e JsonElement como subelementos
As pesquisas no JsonElement
exigem uma pesquisa sequencial das propriedades e, portanto, são relativamente lentas (por exemplo, ao usar TryGetProperty
). System.Text.Json foi criado para minimizar o tempo inicial de análise em vez do tempo de pesquisa. Portanto, use as seguintes abordagens para otimizar o desempenho ao pesquisar por meio de um objeto JsonDocument
:
- Use os enumeradores internos (EnumerateArray e EnumerateObject) em vez de fazer sua própria indexação ou loops.
- Não faça uma pesquisa sequencial no todo
JsonDocument
por meio de cada propriedade usandoRootElement
. Em vez disso, pesquise objetos JSON aninhados com base na estrutura conhecida dos dados JSON. Por exemplo, os exemplos de código anteriores procuram uma propriedadeGrade
em objetosStudent
percorrendo os objetosStudent
e obtendo o valor deGrade
para cada um, em vez de pesquisar em todos os objetosJsonElement
procurando por propriedadesGrade
. Fazer o último resultaria em passagens desnecessárias sobre os mesmos dados.
Comparar JsonElements
Para comparar dois objetos JsonElement
quanto à igualdade, incluindo seus elementos descendentes, use o método 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.
Usar JsonDocument
para gravar JSON
O exemplo a seguir mostra como escrever JSON de um 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()
O código anterior:
- Lê um arquivo JSON, carrega os dados em um
JsonDocument
e grava JSON formatado (bem impresso) em um arquivo. - Usa JsonDocumentOptions para especificar que os comentários no JSON de entrada são permitidos, mas ignorados.
- Quando terminar, chama o gravador Flush. Uma alternativa é deixar o gravador liberar automaticamente quando ele for descartado.
Aqui está um exemplo de entrada JSON a ser processada pelo código de exemplo:
{"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}
O resultado é a seguinte saída JSON bastante impressa:
{
"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 é IDisposable
JsonDocument
cria uma exibição na memória dos dados em um buffer em pool. Portanto, o tipo JsonDocument
implementa IDisposable
e precisa ser usado dentro de um bloco using
.
Retorne apenas JsonDocument
de sua API se você quiser transferir a propriedade de tempo de vida e descartar a responsabilidade para o chamador. Na maioria dos cenários, isso não é necessário. Se o chamador precisar trabalhar com todo o documento JSON, retorne o Clone do RootElement, que é um JsonElement. Se o chamador precisar trabalhar com um elemento específico no documento JSON, retorne o Clone desse JsonElement. Se você retornar o RootElement
ou um subconjunto diretamente sem fazer um Clone
, o chamador não poderá acessar o retornado JsonElement
depois que o proprietário JsonDocument
for descartado.
Aqui está um exemplo que exige que você faça um Clone
:
public JsonElement LookAndLoad(JsonElement source)
{
string json = File.ReadAllText(source.GetProperty("fileName").GetString());
using (JsonDocument doc = JsonDocument.Parse(json))
{
return doc.RootElement.Clone();
}
}
O código anterior espera um JsonElement
que contenha uma propriedade fileName
. Ele abre um arquivo JSON e cria JsonDocument
. O método assume que o chamador deseja trabalhar com todo o documento, então ele retorna Clone
de RootElement
.
Se você receber JsonElement
e estiver retornando um subelemento, não será necessário retornar um subconjunto Clone
. O chamador é responsável por manter ativo o JsonDocument
pertencente ao JsonElement
passado. Por exemplo:
public JsonElement ReturnFileName(JsonElement source)
{
return source.GetProperty("fileName");
}
JsonDocument
com JsonSerializerOptions
Você pode usar JsonSerializer
para serializar e desserializar uma instância de JsonDocument
. No entanto, a implementação para leitura e gravação de instâncias JsonDocument
usando JsonSerializer
é um wrapper por JsonDocument.ParseValue(Utf8JsonReader) e JsonDocument.WriteTo(Utf8JsonWriter). Esse wrapper não encaminha nenhum JsonSerializerOptions
(recursos de serializador) para Utf8JsonReader
ou Utf8JsonWriter
. Por exemplo, se você definir JsonSerializerOptions.DefaultIgnoreCondition como WhenWritingNull e chamar JsonSerializer
com uma sobrecarga que leva JsonSerializerOptions
, as propriedades nulas não serão ignoradas.
O exemplo a seguir ilustra o resultado do uso de métodos que usam um parâmetro JsonSerializerOptions
e serializam uma instância 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; }
}
Se você precisar de recursos JsonSerializerOptions
, use JsonSerializer
com destinos fortemente tipados (como a classe Person
neste exemplo) em vez de JsonDocument
.