Zpracování přetečení JSON nebo použití JsonElement nebo JsonNode v System.Text.Json

Tento článek ukazuje, jak zpracovat přetečení JSON s oborem System.Text.Json názvů. Také ukazuje, jak deserializovat do JsonElement nebo JsonNode, jako alternativu pro jiné scénáře, kde cílový typ nemusí dokonale odpovídat všem deserializovaným JSON.

Zpracování JSON s přetečením

Při deserializaci můžete přijímat data ve formátu JSON, která nejsou reprezentována vlastnostmi cílového typu. Předpokládejme například, že váš cílový typ je tento:

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 JSON, který se má deserializovat, je toto:

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

Pokud deserializujete JSON zobrazený do zobrazeného typu, DatesAvailableSummaryWords nebudou se nikam a vlastnosti ztraceny. Pokud chcete zachytit další data, jako jsou tyto vlastnosti, použijte atribut [JsonExtensionData] na vlastnost typu Dictionary<string,object> nebo 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

Následující tabulka ukazuje výsledek deserializace FORMÁTU JSON zobrazeného dříve do tohoto ukázkového typu. Další data se stanou páry ExtensionData klíč-hodnota vlastnosti:

Vlastnost Hodnota Notes
Date "8/1/2019 12:00:00 AM -07:00"
TemperatureCelsius 0 Neshoda s rozlišováním velkých a malých písmen (temperatureCelsius ve formátu JSON), takže vlastnost není nastavená.
Summary "Hot"
ExtensionData "temperatureCelsius": 25,
"DatesAvailable": ["2019-08-01T00:00:00-07:00","2019-08-02T00:00:00-07:00"],
"SummaryWords": ["Cool","Windy","Humid"]
Vzhledem k tomu, že se případ neshodoval, temperatureCelsius je extra a stane se párem klíč-hodnota ve slovníku.
Každé další pole z JSON se stane párem klíč-hodnota s polem jako objektem hodnoty.

Při serializaci cílového objektu se páry hodnot datového klíče rozšíření stanou vlastnostmi JSON stejně jako v příchozím kódu 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"
  ]
}

Všimněte si, že ExtensionData název vlastnosti se ve formátu JSON nezobrazí. Toto chování umožňuje json provést odezvu bez ztráty dalších dat, která by jinak nebyla deserializována.

Následující příklad ukazuje zpáteční cestu z JSON do deserializovaného objektu a zpět do FORMÁTU 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"
//  ]
//}

Deserializace do JsonElement nebo JsonNode

Pokud chcete být jen flexibilní ohledně toho, co je pro konkrétní vlastnost přijatelné JSON, je alternativou deserializace do JsonElement nebo JsonNode. Libovolnou platnou vlastnost JSON lze deserializovat do JsonElement nebo JsonNode. Zvolte JsonElement vytvoření neměnného objektu nebo JsonNode vytvoření proměnlivého objektu.

Následující příklad ukazuje zpáteční cestu z JSON a zpět do JSON pro třídu, která obsahuje vlastnosti typu JsonElement a 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"
//  ]
//}

Viz také