Language
この記事では、System.Text.Json 名前空間を使用してオーバーフロー JSON を処理する方法を示します。 また、ターゲット型が逆シリアル化対象のすべての JSON と完全に一致しない可能性がある他のシナリオの代替手段として、JsonElement または JsonNode に逆シリアル化する方法も示します。
オーバーフロー JSON の処理
逆シリアル化中に、ターゲット型のプロパティで表されないデータを JSON 内で受け取ることがあります。 たとえば、ターゲット型が次のようになっているとします。
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
逆シリアル化される JSON は次のとおりです。
{
"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"
]
}
表示されている JSON を示されている型に逆シリアル化すると、DatesAvailable と SummaryWords のプロパティは行き先がなくなり、失われます。 これらのプロパティなどの追加データをキャプチャするには、[ JsonExtensionData] 属性をプロパティまたはフィールドに適用します。 サポートされている次のいずれかの宣言を使用します。
- 拡張機能データ メンバーを JsonObjectとして宣言します。
- 拡張機能データ メンバーを
IDictionary<string, object>として宣言します。 - 拡張機能データ メンバーを
IDictionary<string, JsonElement>として宣言します。 - .NET 11 以降では、拡張機能データ メンバーを
IReadOnlyDictionary<string, object>として宣言します。 - .NET 11 以降では、拡張機能データ メンバーを
IReadOnlyDictionary<string, JsonElement>として宣言します。
変更可能なディクショナリ拡張データの場合は、サポートされている IDictionary インターフェイスのいずれかに割り当て可能な任意の型 ( Dictionary<string, JsonElement> など) を使用します。 読み取り専用宣言では、上記の正確な IReadOnlyDictionary インターフェイス型のいずれかを使用する必要があります。
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
IReadOnlyDictionary拡張データ メンバーの場合、.NET 11 はDictionary<string, object>またはDictionary<string, JsonElement>を具体化します。 シリアライザーが既存の値から新しいディクショナリをシードして割り当てるので、メンバーは書き込み可能である必要があります。 受信 JSON プロパティが既存のキーと重複している場合、受信値が優先されます。
次の表では、前に示した JSON をこのサンプル型に逆シリアル化した結果を示します。 余分なデータは、ExtensionData プロパティのキーと値のペアになります。
| プロパティ | 値 | メモ |
|---|---|---|
Date |
"8/1/2019 12:00:00 AM -07:00" |
|
TemperatureCelsius |
0 |
大文字と小文字の区別が一致しないため (JSON では temperatureCelsius)、プロパティは設定されません。 |
Summary |
"Hot" |
|
ExtensionData |
"temperatureCelsius": 25,"DatesAvailable": ["2019-08-01T00:00:00-07:00","2019-08-02T00:00:00-07:00"],"SummaryWords": ["Cool","Windy","Humid"] |
大文字と小文字の区別が一致しなかったため、temperatureCelsius は余分で、ディクショナリ内のキーと値のペアになります。 JSON からの余分な各配列は、値オブジェクトとしての配列を持つキーと値のペアになります。 |
ターゲット オブジェクトがシリアル化されると、拡張データのキーと値のペアは、受信 JSON 内にあった場合と同様に 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"
]
}
JSON には ExtensionData プロパティ名が表示されないことに注意してください。 この動作により、JSON は、逆シリアル化されない余分なデータを失うことなく、ラウンド トリップを行うことができます。
.NET 11 以降では、シリアル化によって拡張データJsonObject含まれる JSON オブジェクトにフラット化されます。
JsonObjectプロパティは、拡張データ メンバー名ではなく、含まれているオブジェクトに直接表示されます。
次の例は、JSON から逆シリアル化されたオブジェクトへ変換し、再び 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"
// ]
//}
JsonElement または JsonNode に逆シリアル化する
特定のプロパティに適した JSON についての柔軟性がほしいだけの場合は、代わりに JsonElement または JsonNode に逆シリアル化する方法があります。 有効な JSON プロパティを、JsonElement または JsonNode に逆シリアル化できます。
不変オブジェクトを作成するには JsonElement を選択し、可変オブジェクトを作成するには JsonNode を選択します。
次の例では、JsonElement 型と JsonNode 型のプロパティを含むクラスを、JSON から変換して JSON に戻すラウンドトリップを示します。
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"
// ]
//}
関連項目
.NET