Taal

Overloop-JSON afhandelen of JsonElement of JsonNode gebruiken

In dit artikel wordt beschreven hoe u overloop-JSON kunt verwerken met de System.Text.Json naamruimte. Het laat ook zien hoe u kunt deserialiseren naar JsonElement of JsonNode, als alternatief in andere scenario's waarbij het doeltype mogelijk niet volledig overeenkomt met alle JSON-gegevens die worden gedeserialiseerd.

JSON-overloop verwerken

Tijdens het deserialiseren ontvangt u mogelijk gegevens in de JSON die niet wordt vertegenwoordigd door eigenschappen van het doeltype. Stel dat uw doeltype dit is:

public class WeatherForecast
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
}
Public Class WeatherForecast
    Public Property [Date] As DateTimeOffset
    Public Property TemperatureCelsius As Integer
    Public Property Summary As String
End Class

En de JSON die moet worden gedeserialiseerd, is dit:

{
  "Date": "2019-08-01T00:00:00-07:00",
  "temperatureCelsius": 25,
  "Summary": "Hot",
  "DatesAvailable": [
    "2019-08-01T00:00:00-07:00",
    "2019-08-02T00:00:00-07:00"
  ],
  "SummaryWords": [
    "Cool",
    "Windy",
    "Humid"
  ]
}

Als u de weergegeven JSON deserialiseert naar het weergegeven type, kunnen de eigenschappen DatesAvailable en SummaryWords nergens terecht en gaan ze verloren. Als u extra gegevens zoals deze eigenschappen wilt vastleggen, past u het kenmerk [JsonExtensionData] toe op een eigenschap of veld. Gebruik een van deze ondersteunde declaraties:

Gebruik voor onveranderbare woordenlijstextensiegegevens elk type dat kan worden toegewezen aan een van de ondersteunde IDictionary interfaces, zoals Dictionary<string, JsonElement>. De declaraties met het kenmerk Alleen-lezen moeten een van de hierboven genoemde exacte IReadOnlyDictionary interfacetypen gebruiken.

public class WeatherForecastWithExtensionData
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
    [JsonExtensionData]
    public Dictionary<string, JsonElement>? ExtensionData { get; set; }
}
Public Class WeatherForecastWithExtensionData
    Public Property [Date] As DateTimeOffset
    Public Property TemperatureCelsius As Integer
    Public Property Summary As String

    <JsonExtensionData>
    Public Property ExtensionData As Dictionary(Of String, Object)

End Class

Voor een IReadOnlyDictionary-lid met extensiegegevens maakt .NET 11 een Dictionary<string, object> of Dictionary<string, JsonElement>. Het lid moet schrijfbaar zijn omdat de serializer de nieuwe dictionary met bestaande waarden initialiseert en deze vervolgens weer toewijst. Als een binnenkomende JSON-eigenschap een bestaande sleutel dupliceert, wint de binnenkomende waarde.

In de volgende tabel ziet u het resultaat van het deserialiseren van de JSON die eerder in dit voorbeeldtype is weergegeven. De extra gegevens worden sleutel-waardeparen van de ExtensionData eigenschap:

Eigenschap Waarde Opmerkingen
Date "8/1/2019 12:00:00 AM -07:00"
TemperatureCelsius 0 Verschil in hoofdlettergebruik (temperatureCelsius in de JSON), waardoor de eigenschap niet wordt ingesteld.
Summary "Hot"
ExtensionData "temperatureCelsius": 25,
"DatesAvailable": ["2019-08-01T00:00:00-07:00","2019-08-02T00:00:00-07:00"],
"SummaryWords": ["Cool","Windy","Humid"]
Omdat de case niet overeenkomt, temperatureCelsius is dit een extra en wordt het een sleutel-waardepaar in de woordenlijst.
Elke extra matrix van de JSON wordt een sleutel-waardepaar, met een matrix als waardeobject.

Wanneer het doelobject wordt geserialiseerd, worden de sleutel-waardeparen voor extensiegegevens JSON-eigenschappen, net zoals in de binnenkomende JSON:

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 0,
  "Summary": "Hot",
  "temperatureCelsius": 25,
  "DatesAvailable": [
    "2019-08-01T00:00:00-07:00",
    "2019-08-02T00:00:00-07:00"
  ],
  "SummaryWords": [
    "Cool",
    "Windy",
    "Humid"
  ]
}

U ziet dat de naam van de ExtensionData eigenschap niet wordt weergegeven in de JSON. Met dit gedrag kan de JSON een retour maken zonder extra gegevens te verliezen die anders niet gedeserialiseerd zouden worden.

Vanaf .NET 11 worden JsonObject-extensiegegevens bij serialisatie afgevlakt in het JSON-object waarin deze zich bevinden. De JsonObject eigenschappen worden rechtstreeks in het bijbehorende object weergegeven, niet onder de naam van het lid van de extensiegegevens.

In het volgende voorbeeld wordt een heen-en-weerconversie van JSON naar een gedeserialiseerd object en terug naar JSON weergegeven:

using System.Text.Json;
using System.Text.Json.Serialization;

namespace RoundtripExtensionData
{
    public class WeatherForecast
    {
        public DateTimeOffset Date { get; set; }
        public int TemperatureCelsius { get; set; }
        public string? Summary { get; set; }
        [JsonExtensionData]
        public Dictionary<string, JsonElement>? ExtensionData { get; set; }
    }

    public class Program
    {
        public static void Main()
        {
            string jsonString =
@"{
  ""Date"": ""2019-08-01T00:00:00-07:00"",
  ""temperatureCelsius"": 25,
  ""Summary"": ""Hot"",
  ""SummaryField"": ""Hot"",
  ""DatesAvailable"": [
    ""2019-08-01T00:00:00-07:00"",
    ""2019-08-02T00:00:00-07:00""
  ],
  ""SummaryWords"": [
    ""Cool"",
    ""Windy"",
    ""Humid""
  ]
}";
            WeatherForecast weatherForecast = 
                JsonSerializer.Deserialize<WeatherForecast>(jsonString)!;

            var serializeOptions = new JsonSerializerOptions { WriteIndented = true };
            jsonString = JsonSerializer.Serialize(weatherForecast, serializeOptions);
            Console.WriteLine($"JSON output:\n{jsonString}\n");
        }
    }
}
// output:
//JSON output:
//{
//  "Date": "2019-08-01T00:00:00-07:00",
//  "TemperatureCelsius": 0,
//  "Summary": "Hot",
//  "temperatureCelsius": 25,
//  "SummaryField": "Hot",
//  "DatesAvailable": [
//    "2019-08-01T00:00:00-07:00",
//    "2019-08-02T00:00:00-07:00"
//  ],
//  "SummaryWords": [
//    "Cool",
//    "Windy",
//    "Humid"
//  ]
//}

Deserialiseren naar JsonElement of JsonNode

Als u alleen flexibel wilt zijn over wat JSON acceptabel is voor een bepaalde eigenschap, is een alternatief om te deserialiseren in JsonElement of JsonNode. Elke geldige JSON-eigenschap kan worden gedeserialiseerd in JsonElement of JsonNode. Kies ervoor JsonElement om een onveranderbaar object te maken of JsonNode om een veranderlijk object te maken.

In het volgende voorbeeld ziet u een retour van JSON en terug naar JSON voor een klasse met eigenschappen van het type JsonElement en JsonNode.

using System.Text.Json;
using System.Text.Json.Nodes;

namespace RoundtripJsonElementAndNode
{
    public class WeatherForecast
    {
        public DateTimeOffset Date { get; set; }
        public int TemperatureCelsius { get; set; }
        public string? Summary { get; set; }
        public JsonElement DatesAvailable { get; set; }
        public JsonNode? SummaryWords { get; set; }
    }
        public class Program
    {
        public static void Main()
        {
            string jsonString =
@"{
  ""Date"": ""2019-08-01T00:00:00-07:00"",
  ""TemperatureCelsius"": 25,
  ""Summary"": ""Hot"",
  ""DatesAvailable"": [
    ""2019-08-01T00:00:00-07:00"",
    ""2019-08-02T00:00:00-07:00""
  ],
  ""SummaryWords"": [
    ""Cool"",
    ""Windy"",
    ""Humid""
  ]
}";
            WeatherForecast? weatherForecast = 
                JsonSerializer.Deserialize<WeatherForecast>(jsonString);

            var serializeOptions = new JsonSerializerOptions { WriteIndented = true };
            jsonString = JsonSerializer.Serialize(weatherForecast, serializeOptions);
            Console.WriteLine(jsonString);
        }
    }
}
// output:
//{
//  "Date": "2019-08-01T00:00:00-07:00",
//  "TemperatureCelsius": 25,
//  "Summary": "Hot",
//  "DatesAvailable": [
//    "2019-08-01T00:00:00-07:00",
//    "2019-08-02T00:00:00-07:00"
//  ],
//  "SummaryWords": [
//    "Cool",
//    "Windy",
//    "Humid"
//  ]
//}

Zie ook