How to handle overflow JSON or use JsonElement or JsonNode in (Jak obsługiwać przepełnienie kodu JSON lub JsonElement lub JsonNode) System.Text.Json

W tym artykule pokazano, jak obsługiwać przepełnienie kodu JSON przy użyciu System.Text.Json przestrzeni nazw. Pokazuje również, jak deserializować w JsonElement systemie lub JsonNode, jako alternatywę dla innych scenariuszy, w których typ docelowy może nie być idealnie zgodny ze wszystkimi deserializacji JSON.

Obsługa przepełnienia kodu JSON

Podczas deserializacji można odbierać dane w formacie JSON, które nie są reprezentowane przez właściwości typu docelowego. Załóżmy na przykład, że twój typ docelowy to:

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

A kod JSON, który ma zostać zdeserializowany, jest następujący:

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

Jeśli deserializujesz kod JSON wyświetlany w wyświetlonym typie, DatesAvailable właściwości i SummaryWords nie mają miejsca do przejścia i zostaną utracone. Aby przechwycić dodatkowe dane, takie jak te właściwości, zastosuj atrybut [JsonExtensionData] do właściwości typu Dictionary<string,object> lub Dictionary<string,JsonElement>:

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

W poniższej tabeli przedstawiono wynik deserializacji kodu JSON pokazanego wcześniej w tym przykładzie. Dodatkowe dane stają się parami ExtensionData klucz-wartość właściwości:

Właściwości Wartość Uwagi
Date "8/1/2019 12:00:00 AM -07:00"
TemperatureCelsius 0 Niezgodność z rozróżnianą wielkością liter (temperatureCelsius w formacie JSON), więc właściwość nie jest ustawiona.
Summary "Hot"
ExtensionData "temperatureCelsius": 25,
"DatesAvailable": ["2019-08-01T00:00:00-07:00","2019-08-02T00:00:00-07:00"],
"SummaryWords": ["Cool","Windy","Humid"]
Ponieważ przypadek nie jest zgodny, temperatureCelsius jest dodatkową i staje się parą klucz-wartość w słowniku.
Każda dodatkowa tablica z formatu JSON staje się parą klucz-wartość z tablicą jako obiekt wartości.

Gdy obiekt docelowy jest serializowany, pary wartości klucza danych rozszerzenia stają się właściwościami JSON tak samo jak w przychodzącym formacie 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"
  ]
}

Zwróć uwagę, że ExtensionData nazwa właściwości nie jest wyświetlana w formacie JSON. To zachowanie pozwala kodowi JSON wykonać rundę bez utraty dodatkowych danych, które w przeciwnym razie nie zostaną zdeserializowane.

W poniższym przykładzie pokazano zaokrągloną podróż z pliku JSON do zdeserializowanego obiektu i z powrotem do formatu 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"
//  ]
//}

Deserializowanie do elementu JsonElement lub JsonNode

Jeśli chcesz być po prostu elastyczny co do tego, co JSON jest akceptowalne dla określonej właściwości, alternatywą jest deserializowanie do JsonElement lub JsonNode. Każda prawidłowa właściwość JSON może zostać zdeserializowana do JsonElement elementu lub JsonNode. Wybierz JsonElement , aby utworzyć niezmienny obiekt lub JsonNode utworzyć obiekt modyfikowalny.

W poniższym przykładzie przedstawiono rundę z formatu JSON i z powrotem do formatu JSON dla klasy zawierającej właściwości typu JsonElement i 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"
//  ]
//}

Zobacz też