Språk

Hantera spill-JSON eller använda JsonElement eller JsonNode

Den här artikeln visar hur du hanterar spill-JSON med System.Text.Json namnområdet. Den visar också hur du deserialiserar till JsonElement eller JsonNode, som ett alternativ för andra scenarier där måltypen kanske inte helt matchar alla JSON som deserialiseras.

Hantera överskotts-JSON

Vid deserialisering kan du få data i JSON som inte representeras av egenskaper av måltypen. Anta till exempel att din måltyp är följande:

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

Och JSON som ska deserialiseras är följande:

{
  "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"
  ]
}

Om du deserialiserar JSON som visas i den typ som visas har DatesAvailable egenskaperna och SummaryWords ingenstans att ta vägen och går förlorade. Om du vill samla in extra data som dessa egenskaper använder du attributet [JsonExtensionData] på en egenskap eller ett fält. Använd någon av följande deklarationer som stöds:

För föränderliga ordlistetilläggsdata använder du valfri typ som kan tilldelas till något av de gränssnitt som stöds IDictionary , till exempel Dictionary<string, JsonElement>. Skrivskyddade deklarationer måste använda någon av de exakta IReadOnlyDictionary gränssnittstyper som anges ovan.

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

För en IReadOnlyDictionary tilläggsdatamedlem materialiserar .NET 11 en Dictionary<string, object> eller Dictionary<string, JsonElement>. Medlemmen måste vara skrivbar eftersom serialiseraren frön den nya ordlistan från befintliga värden och tilldelar tillbaka den. Om en inkommande JSON-egenskap duplicerar en befintlig nyckel vinner det inkommande värdet.

I följande tabell visas resultatet av deserialisering av JSON som visades tidigare i den här exempeltypen. De extra uppgifterna omvandlas till nyckel/värde-par i egenskapen ExtensionData:

Egenskap Värde Anteckningar
Date "8/1/2019 12:00:00 AM -07:00"
TemperatureCelsius 0 Skiftlägeskänslig matchning (temperatureCelsius i JSON), så egenskapen har inte angetts.
Summary "Hot"
ExtensionData "temperatureCelsius": 25,
"DatesAvailable": ["2019-08-01T00:00:00-07:00","2019-08-02T00:00:00-07:00"],
"SummaryWords": ["Cool","Windy","Humid"]
Eftersom fallet inte matchade temperatureCelsius är det ett extra och blir ett nyckel/värde-par i ordlistan.
Varje extra matris från JSON blir ett nyckel/värde-par, med en matris som värdeobjekt.

När målobjektet serialiseras blir tilläggsdatanyckelparen JSON-egenskaper precis som i den inkommande JSON:en:

{
  "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"
  ]
}

Observera att egenskapsnamnet ExtensionData inte visas i JSON. Med det här beteendet kan JSON göra en tur och retur utan att förlora några extra data som annars inte skulle deserialiseras.

Från och med .NET 11 jämnar serialiseringen ut tilläggsdata JsonObject till det innehållande JSON-objektet. Egenskaperna JsonObject visas direkt i det innehållande objektet, inte under medlemsnamnet extension-data.

I följande exempel visas en tur och retur-resa från JSON till ett deserialiserat objekt och tillbaka till JSON:

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"
//  ]
//}

Deserialisera till JsonElement eller JsonNode

Om du bara vill vara flexibel om vad JSON är acceptabelt för en viss egenskap är ett alternativ att deserialisera till JsonElement eller JsonNode. Alla giltiga JSON-egenskaper kan deserialiseras till JsonElement eller JsonNode. Välj JsonElement att skapa ett oföränderligt objekt eller JsonNode skapa ett föränderligt objekt.

I följande exempel visas en tur- och returresa från JSON och tillbaka till JSON för en klass som innehåller egenskaper av typen JsonElement och 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"
//  ]
//}

Se även