Partilhar via


Como usar um modelo de objeto de documento JSON em System.Text.Json

Este artigo mostra como usar um modelo de objeto de documento JSON (DOM) para acesso aleatório a dados em uma carga JSON útil.

Opções de JSON DOM

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 Utf8JsonReadero . Os elementos JSON que compõem a carga útil podem ser acessados através do JsonElement tipo. O JsonElement tipo fornece enumeradores de matriz e objeto junto com APIs para converter texto JSON em tipos .NET comuns. JsonDocument expõe uma RootElement propriedade. Para obter mais informações, consulte Usar JsonDocument mais adiante neste artigo.

  • JsonNode e as classes que derivam dele no System.Text.Json.Nodes namespace fornecem a capacidade de criar um DOM mutável. Os elementos JSON que compõem a carga útil podem ser acessados por meio dos JsonNodetipos , JsonObject, JsonArray, JsonValue, e JsonElement . Para obter mais informações, consulte Usar JsonNode mais adiante neste artigo.

Considere os seguintes fatores ao escolher entre JsonDocument e JsonNode:

  • O JsonNode DOM pode ser alterado após a sua criação. O JsonDocument DOM é imutável.
  • O JsonDocument DOM fornece acesso mais rápido aos seus dados.

Utilizar o comando JsonNode

O exemplo a seguir mostra como usar JsonNode e os outros tipos no System.Text.Json.Nodes namespace para:

  • Criar um DOM a partir de uma cadeia de caracteres JSON
  • Escreva JSON a partir 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"
    }
}

Crie um DOM JsonNode com inicializadores de objeto e faça 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 uma carga 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 de 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 Students matriz que têm uma Grade propriedade.
  • Atribui uma nota padrão de 70 para alunos que não têm nota.
  • Obtém o número de alunos da Count propriedade de JsonArray.

JsonNode com JsonSerializerOptions

Você pode usar JsonSerializer para serializar e desserializar uma instância do JsonNode. No entanto, se você usar uma sobrecarga que leva JsonSerializerOptions, a instância de opções é usada apenas 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 JsonNode métodos que tomam um JsonSerializerOptions parâmetro: 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 JsonSerializerOptions parâmetro e serializam uma JsonNode instância:

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 diferentes de conversores personalizados, use JsonSerializer com destinos fortemente tipados (como a Person classe neste exemplo) em vez de JsonNodeJsonSerializerOptions .

Manipular a ordem da propriedade

JsonObject é um dos elementos na carga útil de um JsonNode, e representa um objeto JSON mutável. Embora o tipo seja modelado como um IDictionary<string, JsonNode>, onde 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) efetivamente modelam 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 da propriedade.

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 JsonNode objetos para igualdade, incluindo seus elementos descendentes, use o JsonNode.DeepEquals(JsonNode, JsonNode) método.

Utilizar o comando JsonDocument

O exemplo a seguir mostra como usar a JsonDocument classe 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:

  • Assume que o JSON a ser analisado está em uma cadeia de caracteres chamada jsonString.
  • Calcula uma nota média para objetos em uma Students matriz que têm uma Grade propriedade.
  • Atribui uma nota padrão de 70 para alunos que não têm nota.
  • Cria a JsonDocument instância em uma using instrução porque JsonDocument implementa IDisposable. Depois que uma JsonDocument instância é descartada, você também perde o acesso a todas as instâncias JsonElement . Para manter o acesso a uma JsonElement instância, faça uma cópia dela antes que a instância pai JsonDocument seja descartada. Para fazer uma cópia, ligue JsonElement.Clonepara . Para obter mais informações, consulte JsonDocument is IDisposable.

O código de exemplo anterior conta os alunos incrementando uma count variável a cada iteração. Uma alternativa é chamar GetArrayLength, como 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 esse 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 obter um exemplo semelhante que usa JsonNode em vez de , consulte Exemplo de nota média do JsonDocumentJsonNode.

Como pesquisar subelementos JsonDocument e JsonElement

As pesquisas exigem JsonElement uma pesquisa sequencial das propriedades e, portanto, são relativamente lentas (por exemplo, ao usar TryGetProperty). System.Text.Json foi projetado para minimizar o tempo de análise inicial em vez do tempo de pesquisa. Portanto, use as seguintes abordagens para otimizar o desempenho ao pesquisar um JsonDocument objeto:

  • 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 em todos JsonDocument os imóveis usando RootElemento . Em vez disso, pesquise em objetos JSON aninhados com base na estrutura conhecida dos dados JSON. Por exemplo, os exemplos de código anteriores procuram uma Grade propriedade em Student objetos fazendo looping pelos Student objetos e obtendo o valor de para cada um, em vez de Grade pesquisar todos os JsonElement objetos procurando Grade propriedades. Fazer isso resultaria em repasses desnecessários sobre os mesmos dados.

Comparar JsonElements

Para comparar dois JsonElement objetos para igualdade, incluindo seus elementos descendentes, use o JsonElement.DeepEquals(JsonElement, JsonElement) método.

JsonElement left = JsonDocument.Parse("10e-3").RootElement;
JsonElement right = JsonDocument.Parse("0.01").RootElement;
bool equal = JsonElement.DeepEquals(left, right);
Console.WriteLine(equal); // True.

Use JsonDocument para escrever JSON

O exemplo a seguir mostra como escrever JSON a partir 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 JsonDocumente 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 Flush o escritor. Uma alternativa é deixar o gravador lavar automaticamente quando estiver 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 impressa com elegância:

{
  "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 JsonDocument tipo implementa e precisa ser usado dentro de IDisposable um using bloco.

Só devolva um JsonDocument da sua API se quiser transferir a propriedade vitalícia 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 RootElementdo , que é um JsonElementarquivo . Se o chamador precisar trabalhar com um elemento específico dentro do documento JSON, retorne o Clone .JsonElement Se você retornar o RootElement ou um subelemento diretamente sem fazer um Clone, o chamador não poderá acessar o devolvido JsonElement depois que o JsonDocument que o possui for descartado.

Aqui está um exemplo que requer 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 contém uma fileName propriedade. Ele abre o arquivo JSON e cria um JsonDocumentarquivo . O método pressupõe que o chamador deseja trabalhar com o documento inteiro, portanto, ele retorna o Clone do RootElement.

Se você receber um JsonElement e estiver retornando um subelemento, não será necessário retornar um Clone dos subelementos. O interlocutor é responsável por manter vivo aquele JsonDocument a que pertence o passageiro JsonElement . 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 do JsonDocument. No entanto, a implementação para instâncias de leitura e gravação JsonDocument usando JsonSerializer é um wrapper sobre o JsonDocument.ParseValue(Utf8JsonReader) e JsonDocument.WriteTo(Utf8JsonWriter). Este wrapper não encaminha nenhum JsonSerializerOptions (recursos do 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 JsonSerializerOptions parâmetro e serializam uma JsonDocument instância:

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 do , use JsonSerializer com destinos fortemente tipados (como a Person classe neste exemplo) em vez de JsonDocumentJsonSerializerOptions.

Consulte também