【C#】System.Text.JsonとNewtonsoft.Jsonで学ぶJSONデシリアライズの基本と実践テクニック
C#でJSONを扱うにはSystem.Text.Json
とNewtonsoft.Json
が主流で、どちらもJsonSerializer.Deserialize<T>
やJsonConvert.DeserializeObject<T>
で文字列をオブジェクト化できます。
型とプロパティ名を合わせる、属性で差異を補正する、カスタムコンバーターで特殊変換に対応すれば柔軟に取り込めます。
軽量で速い標準ライブラリ、機能豊富なJson.NETを用途で使い分けると効率的です。
JSONデシリアライズの基礎知識
JSON(JavaScript Object Notation)は、軽量で読みやすいデータ交換フォーマットとして広く利用されています。
C#でJSONデータを扱う際には、JSON文字列をC#のオブジェクトに変換する「デシリアライズ」が重要な役割を果たします。
ここでは、JSONのシリアライズとデシリアライズの違い、C#でJSONを扱うメリット、そして主要なJSONライブラリの位置付けについて詳しく解説します。
シリアライズとデシリアライズの違い
シリアライズとデシリアライズは、データの変換に関わる対になる処理です。
- シリアライズは、C#のオブジェクトやデータ構造をJSON形式の文字列に変換する処理です
- デシリアライズは、その逆で、JSON形式の文字列をC#のオブジェクトに変換する処理を指します
たとえば、Web APIから取得したJSONレスポンスをC#のクラスに変換して扱いたい場合は、デシリアライズを行います。
逆に、C#のオブジェクトをJSON形式に変換して外部に送信したい場合はシリアライズを使います。
この2つの処理はセットで使われることが多く、JSONを介したデータの送受信や保存に欠かせません。
具体例として、以下のようなJSON文字列とC#のクラスを考えます。
{"Name":"山田太郎","Age":30}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
このJSON文字列をPerson
クラスのインスタンスに変換するのがデシリアライズです。
逆に、Person
オブジェクトをJSON文字列に変換するのがシリアライズです。
C#で扱うメリット
C#でJSONを扱うメリットは多岐にわたります。
主なポイントを挙げると以下の通りです。
- 型安全なデータ操作が可能
JSON文字列を直接扱うのではなく、C#のクラスにマッピングすることで、型安全にデータを操作できます。
これにより、誤った型のデータアクセスやプロパティの存在チェックがコンパイル時に行え、バグを減らせます。
- 豊富なライブラリとツールのサポート
.NET環境には、System.Text.Json
やNewtonsoft.Json
などの強力なJSON処理ライブラリが標準またはサードパーティで提供されています。
これらは高速かつ柔軟な機能を備えており、開発効率を高めます。
- Web APIとの親和性が高い
RESTful APIやWebサービスの多くはJSONをデータフォーマットとして採用しています。
C#でJSONを簡単にデシリアライズできるため、APIクライアントの開発がスムーズに行えます。
- クロスプラットフォーム対応
.NET Coreや.NET 5以降の環境では、WindowsだけでなくLinuxやmacOSでも動作します。
JSONはプラットフォームに依存しないフォーマットなので、C#でのJSON処理はクロスプラットフォーム開発に適しています。
- メンテナンス性の向上
JSONデータをC#のクラスにマッピングすることで、コードの可読性や保守性が向上します。
データ構造の変更もクラス定義の修正だけで済み、影響範囲を限定できます。
これらのメリットにより、C#はJSONを扱う際に非常に適した言語であると言えます。
主要ライブラリの位置付け
C#でJSONのデシリアライズを行う際に利用される主要なライブラリは以下の3つです。
ライブラリ名 | 提供元 | 特徴・用途 |
---|---|---|
System.Text.Json | Microsoft (.NET) | .NET Core 3.0以降の標準ライブラリ。高速で軽量、標準機能が充実。Unicodeエスケープの制御など細かい設定も可能です。 |
Newtonsoft.Json (Json.NET) | サードパーティ | 長年使われている実績豊富なライブラリ。柔軟な設定や拡張性が高く、複雑なシナリオに対応しやすい。 |
DataContractJsonSerializer | Microsoft (.NET) | .NET Framework標準のシリアライザ。属性ベースの制御が特徴。レガシー環境での利用が多い。 |
System.Text.Json
.NET Core 3.0以降で標準搭載されているため、追加のパッケージをインストールせずに利用できます。
パフォーマンスが高く、軽量であることが特徴です。
属性による制御やカスタムコンバーターの実装も可能で、最新の.NET環境で推奨されるライブラリです。
Newtonsoft.Json (Json.NET)
長期間にわたりC#のJSON処理のデファクトスタンダードとして使われてきました。
多彩な機能を持ち、複雑なJSON構造やポリモーフィックな型の扱い、LINQ to JSONなど高度な操作が可能です。
標準ライブラリよりも柔軟性が高い反面、パフォーマンスはやや劣る場合があります。
DataContractJsonSerializer
.NET Framework時代から存在する標準のJSONシリアライザです。
[DataContract]
や[DataMember]
属性を使って明示的にシリアライズ対象を指定します。
レガシーな環境やWCFサービスとの連携で使われることが多いですが、最近はSystem.Text.Json
やNewtonsoft.Json
に置き換えられるケースが増えています。
これらのライブラリは用途や環境に応じて使い分けられます。
最新の.NET環境であればSystem.Text.Json
が推奨されますが、既存のプロジェクトや複雑な要件がある場合はNewtonsoft.Json
が選ばれることも多いです。
デシリアライズの基本を理解した上で、適切なライブラリを選択することが重要です。
System.Text.Jsonのデシリアライズ
JsonSerializer.Deserializeの基本構文
クラス定義と型パラメータ
System.Text.Json
のデシリアライズは、JsonSerializer.Deserialize<T>
メソッドを使って行います。
ここでT
はデシリアライズ先の型を指定します。
JSON文字列をC#のクラスに変換するためには、まず対象のクラスを定義します。
using System;
using System.Text.Json;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
public class Program
{
public static void Main()
{
string jsonString = "{\"Name\":\"山田太郎\",\"Age\":30}";
// JSON文字列をPerson型にデシリアライズ
Person person = JsonSerializer.Deserialize<Person>(jsonString);
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}
}
Name: 山田太郎, Age: 30
この例では、jsonString
のJSONデータをPerson
クラスのインスタンスに変換しています。
Deserialize<T>
はジェネリックメソッドで、型パラメータT
に変換先の型を指定することで、型安全にデシリアライズできます。
非同期API
System.Text.Json
は非同期でのデシリアライズもサポートしています。
大きなJSONデータをストリームから読み込む場合に有効です。
JsonSerializer.DeserializeAsync<T>
メソッドを使い、Stream
から非同期にデシリアライズします。
using System;
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
public class Program
{
public static async Task Main()
{
string jsonString = "{\"Name\":\"山田太郎\",\"Age\":30}";
using var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(jsonString));
// ストリームから非同期にデシリアライズ
Person person = await JsonSerializer.DeserializeAsync<Person>(stream);
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}
}
Name: 山田太郎, Age: 30
非同期APIはI/O待ちの間に他の処理を行いたい場合に便利です。
Web APIのレスポンスをストリームで受け取るケースなどで活用されます。
オプションの活用
PropertyNameCaseInsensitive
JSONのプロパティ名とC#のプロパティ名の大文字・小文字が異なる場合でもマッチさせたいときに使います。
デフォルトでは大文字・小文字を区別するため、PropertyNameCaseInsensitive
をtrue
に設定します。
using System;
using System.Text.Json;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
public class Program
{
public static void Main()
{
string jsonString = "{\"name\":\"山田太郎\",\"age\":30}";
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
Person person = JsonSerializer.Deserialize<Person>(jsonString, options);
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}
}
Name: 山田太郎, Age: 30
この設定により、JSONのname
やage
がName
やAge
に正しくマッピングされます。
Encoder設定で日本語を扱う
デフォルトでは、System.Text.Json
は非ASCII文字を\uXXXX
形式でエスケープします。
日本語などの文字をそのまま出力したい場合は、JavaScriptEncoder.UnsafeRelaxedJsonEscaping
を指定します。
using System;
using System.Text.Json;
using System.Text.Encodings.Web;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
public class Program
{
public static void Main()
{
var person = new Person { Name = "山田太郎", Age = 30 };
var options = new JsonSerializerOptions
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
WriteIndented = true
};
string jsonString = JsonSerializer.Serialize(person, options);
Console.WriteLine(jsonString);
}
}
{
"Name": "山田太郎",
"Age": 30
}
この設定はシリアライズ時の例ですが、デシリアライズ時も同様に日本語を含むJSONを扱う際に役立ちます。
DefaultIgnoreCondition
デシリアライズ時に、JSONに存在しないプロパティを無視したい場合や、null値の扱いを制御したい場合に使います。
DefaultIgnoreCondition
にJsonIgnoreCondition.WhenWritingNull
などを設定して、null値のシリアライズ・デシリアライズ挙動を調整できます。
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
public class Person
{
public string Name { get; set; }
public int? Age { get; set; }
}
public class Program
{
public static void Main()
{
string jsonString = "{\"Name\":\"山田太郎\"}";
var options = new JsonSerializerOptions
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
Person person = JsonSerializer.Deserialize<Person>(jsonString, options);
Console.WriteLine($"Name: {person.Name}, Age: {(person.Age.HasValue ? person.Age.Value.ToString() : "null")}");
}
}
Name: 山田太郎, Age: null
この例では、JSONにAge
が存在しなくてもエラーにならず、Age
はnull
として扱われます。
属性による制御
JsonPropertyName
JSONのプロパティ名とC#のプロパティ名が異なる場合に、[JsonPropertyName]
属性でマッピングを指定します。
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
public class Person
{
[JsonPropertyName("full_name")]
public string Name { get; set; }
public int Age { get; set; }
}
public class Program
{
public static void Main()
{
string jsonString = "{\"full_name\":\"山田太郎\",\"Age\":30}";
Person person = JsonSerializer.Deserialize<Person>(jsonString);
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}
}
Name: 山田太郎, Age: 30
この属性を使うことで、JSONのfull_name
がName
プロパティに正しくマッピングされます。
JsonIgnore
特定のプロパティをデシリアライズやシリアライズの対象から除外したい場合に使います。
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
public class Person
{
public string Name { get; set; }
[JsonIgnore]
public int Age { get; set; }
}
public class Program
{
public static void Main()
{
string jsonString = "{\"Name\":\"山田太郎\",\"Age\":30}";
Person person = JsonSerializer.Deserialize<Person>(jsonString);
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}
}
Name: 山田太郎, Age: 0
Age
はJSONから無視されるため、デフォルト値の0
になります。
JsonInclude
プライベートや読み取り専用のプロパティをデシリアライズ対象に含めたい場合に使います。
通常はパブリックなプロパティのみが対象ですが、[JsonInclude]
を付けると非公開メンバーも対象になります。
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
public class Person
{
public string Name { get; set; }
[JsonInclude]
public int Age { get; private set; }
public Person() { }
public Person(int age)
{
Age = age;
}
}
public class Program
{
public static void Main()
{
string jsonString = "{\"Name\":\"山田太郎\",\"Age\":30}";
Person person = JsonSerializer.Deserialize<Person>(jsonString);
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}
}
Name: 山田太郎, Age: 30
Age
はプライベートセッターですが、[JsonInclude]
によりデシリアライズ時に値が設定されます。
カスタムコンバーターの実装
変換対象の選定
JSONの型とC#の型が一致しない場合や、特殊な変換が必要な場合はカスタムコンバーターを作成します。
例えば、JSONの数値が文字列として表現されている場合や、日付のフォーマットが標準と異なる場合などです。
JsonConverter<T>の書き方
JsonConverter<T>
を継承し、Read
とWrite
メソッドをオーバーライドして変換処理を実装します。
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
public class StringToIntConverter : JsonConverter<int>
{
public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
// JSONの値が文字列の場合にintに変換
if (reader.TokenType == JsonTokenType.String)
{
string stringValue = reader.GetString();
if (int.TryParse(stringValue, out int value))
{
return value;
}
throw new JsonException("数値に変換できません");
}
else if (reader.TokenType == JsonTokenType.Number)
{
return reader.GetInt32();
}
throw new JsonException("不正なトークンタイプです");
}
public override void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options)
{
// intを文字列として書き出す
writer.WriteStringValue(value.ToString());
}
}
public class Person
{
public string Name { get; set; }
[JsonConverter(typeof(StringToIntConverter))]
public int Age { get; set; }
}
public class Program
{
public static void Main()
{
string jsonString = "{\"Name\":\"山田太郎\",\"Age\":\"30\"}";
Person person = JsonSerializer.Deserialize<Person>(jsonString);
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}
}
Name: 山田太郎, Age: 30
この例では、Age
がJSONで文字列として表現されていても、カスタムコンバーターで正しく整数に変換しています。
サンプルシナリオ別実装
DateTimeのフォーマット変換
JSONの日付フォーマットが標準のISO 8601形式でない場合、カスタムコンバーターで変換します。
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Globalization;
public class CustomDateTimeConverter : JsonConverter<DateTime>
{
private const string Format = "yyyyMMdd";
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
string dateString = reader.GetString();
if (DateTime.TryParseExact(dateString, Format, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime date))
{
return date;
}
throw new JsonException("日付の形式が不正です");
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString(Format));
}
}
public class Event
{
public string Title { get; set; }
[JsonConverter(typeof(CustomDateTimeConverter))]
public DateTime Date { get; set; }
}
public class Program
{
public static void Main()
{
string jsonString = "{\"Title\":\"会議\",\"Date\":\"20230615\"}";
Event ev = JsonSerializer.Deserialize<Event>(jsonString);
Console.WriteLine($"Title: {ev.Title}, Date: {ev.Date:yyyy-MM-dd}");
}
}
Title: 会議, Date: 2023-06-15
数値を文字列から読み込む
前述のStringToIntConverter
のように、数値が文字列で表現されているケースに対応します。
カスタムコンバーターを使うことで、JSONの柔軟な形式に対応可能です。
不定形JSONのマッピング
JSONの構造が固定されていない場合、JsonDocument
やJsonElement
を使って動的に解析します。
using System;
using System.Text.Json;
public class Program
{
public static void Main()
{
string jsonString = "{\"Name\":\"山田太郎\",\"Attributes\":{\"Height\":170,\"Weight\":65}}";
using JsonDocument doc = JsonDocument.Parse(jsonString);
JsonElement root = doc.RootElement;
string name = root.GetProperty("Name").GetString();
JsonElement attributes = root.GetProperty("Attributes");
int height = attributes.GetProperty("Height").GetInt32();
int weight = attributes.GetProperty("Weight").GetInt32();
Console.WriteLine($"Name: {name}, Height: {height}, Weight: {weight}");
}
}
Name: 山田太郎, Height: 170, Weight: 65
この方法は、事前にクラスを定義できない不定形のJSONを扱う際に有効です。
パフォーマンス向上策
Source Generationの活用
.NET 6以降では、System.Text.Json
のソースジェネレーション機能を使い、コンパイル時にシリアライズ・デシリアライズコードを生成して高速化できます。
JsonSerializerContext
を継承したクラスを作成し、対象の型を指定します。
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
[JsonSerializable(typeof(Person))]
public partial class PersonJsonContext : JsonSerializerContext
{
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
public class Program
{
public static void Main()
{
string jsonString = "{\"Name\":\"山田太郎\",\"Age\":30}";
Person person = JsonSerializer.Deserialize(jsonString, PersonJsonContext.Default.Person);
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}
}
Name: 山田太郎, Age: 30
この方法は、リフレクションを使わずに高速にデシリアライズできるため、大量データ処理に適しています。
Utf8JsonReaderの直接利用
低レベルAPIのUtf8JsonReader
を使うと、JSONを高速かつ細かく制御しながら読み取れます。
複雑なJSONやパフォーマンス重視の処理で使われます。
using System;
using System.Text;
using System.Text.Json;
public class Program
{
public static void Main()
{
string jsonString = "{\"Name\":\"山田太郎\",\"Age\":30}";
byte[] jsonBytes = Encoding.UTF8.GetBytes(jsonString);
var reader = new Utf8JsonReader(jsonBytes);
string name = null;
int age = 0;
while (reader.Read())
{
if (reader.TokenType == JsonTokenType.PropertyName)
{
string propertyName = reader.GetString();
reader.Read();
if (propertyName == "Name")
{
name = reader.GetString();
}
else if (propertyName == "Age")
{
age = reader.GetInt32();
}
}
}
Console.WriteLine($"Name: {name}, Age: {age}");
}
}
Name: 山田太郎, Age: 30
Utf8JsonReader
はストリーム処理や部分的なJSON解析に向いていますが、コードが複雑になるため、通常はJsonSerializer
を使うことが多いです。
Newtonsoft.Json(Json.NET)のデシリアライズ
JsonConvert.DeserializeObjectの基本構文
型指定の方法
Newtonsoft.Json
のデシリアライズは、JsonConvert.DeserializeObject<T>
メソッドを使います。
T
に変換先の型を指定することで、JSON文字列をC#のオブジェクトに変換します。
using System;
using Newtonsoft.Json;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
public class Program
{
public static void Main()
{
string jsonString = "{\"Name\":\"山田太郎\",\"Age\":30}";
Person person = JsonConvert.DeserializeObject<Person>(jsonString);
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}
}
Name: 山田太郎, Age: 30
型を指定することで、JSONの内容がPerson
クラスのプロパティにマッピングされます。
型を指定しない場合はobject
型としてデシリアライズされ、動的に扱うことになりますが、型安全性が低下します。
GenericCollectionの取り扱い
リストや配列などのコレクションをデシリアライズする場合も、型パラメータにコレクション型を指定します。
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
public class Program
{
public static void Main()
{
string jsonString = "[{\"Name\":\"山田太郎\",\"Age\":30},{\"Name\":\"鈴木花子\",\"Age\":25}]";
List<Person> people = JsonConvert.DeserializeObject<List<Person>>(jsonString);
foreach (var person in people)
{
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}
}
}
Name: 山田太郎, Age: 30
Name: 鈴木花子, Age: 25
List<T>
やT[]
などのジェネリックコレクションを指定することで、複数のオブジェクトをまとめてデシリアライズできます。
SerializerSettingsの構成
JsonSerializerSettings
を使うと、デシリアライズ時の挙動を細かく制御できます。
NullValueHandling
NullValueHandling
は、JSONのnull
値の扱いを制御します。
Ignore
に設定すると、null
値のプロパティは無視され、既存のオブジェクトの値が変更されません。
using System;
using Newtonsoft.Json;
public class Person
{
public string Name { get; set; }
public string Nickname { get; set; }
}
public class Program
{
public static void Main()
{
string jsonString = "{\"Name\":\"山田太郎\",\"Nickname\":null}";
var settings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
};
Person person = JsonConvert.DeserializeObject<Person>(jsonString, settings);
Console.WriteLine($"Name: {person.Name}, Nickname: {(person.Nickname ?? "null")}");
}
}
Name: 山田太郎, Nickname: null
この例では、Nickname
がnull
でも無視されるため、既存の値が保持されます。
DefaultValueHandling
DefaultValueHandling
は、デフォルト値のプロパティの扱いを制御します。
Ignore
に設定すると、デフォルト値のプロパティはシリアライズ・デシリアライズ時に無視されます。
using System;
using Newtonsoft.Json;
public class Person
{
public string Name { get; set; }
public int Age { get; set; } = 20;
}
public class Program
{
public static void Main()
{
string jsonString = "{\"Name\":\"山田太郎\",\"Age\":0}";
var settings = new JsonSerializerSettings
{
DefaultValueHandling = DefaultValueHandling.Ignore
};
Person person = JsonConvert.DeserializeObject<Person>(jsonString, settings);
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}
}
Name: 山田太郎, Age: 0
Age
が0
(intのデフォルト値)でも無視されるため、既存の値が保持されます。
MissingMemberHandling
MissingMemberHandling
は、JSONに存在しないプロパティがC#のクラスにある場合の挙動を制御します。
Error
に設定すると、JSONに存在しないメンバーがあると例外が発生します。
using System;
using Newtonsoft.Json;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
// JSON に必須項目として存在しなければ例外を発生させる
[JsonProperty(Required = Required.Always)]
public string Address { get; set; }
}
public class Program
{
public static void Main()
{
string jsonString = "{\"Name\":\"山田太郎\",\"Age\":30}";
var settings = new JsonSerializerSettings
{
MissingMemberHandling = MissingMemberHandling.Error
};
try
{
// Address が JSON に無いため、ここで例外が投げられる
Person person = JsonConvert.DeserializeObject<Person>(jsonString, settings);
}
catch (JsonSerializationException ex)
{
Console.WriteLine($"例外発生: {ex.Message}");
}
}
}
例外発生: Required property 'Address' not found in JSON. Path '', line 1, position 31.
この設定は、JSONとクラスの整合性を厳密にチェックしたい場合に有効です。
属性で細かく制御
JsonProperty
[JsonProperty]
属性は、JSONのプロパティ名とC#のプロパティ名をマッピングしたり、シリアライズ・デシリアライズの挙動を細かく制御したりできます。
using System;
using Newtonsoft.Json;
public class Person
{
[JsonProperty("full_name")]
public string Name { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public int Age { get; set; }
}
public class Program
{
public static void Main()
{
string jsonString = "{\"full_name\":\"山田太郎\"}";
Person person = JsonConvert.DeserializeObject<Person>(jsonString);
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}
}
Name: 山田太郎, Age: 0
full_name
がName
にマッピングされ、Age
はJSONに存在しなくてもデフォルト値の0
が設定されます。
JsonIgnore
[JsonIgnore]
属性は、特定のプロパティをシリアライズ・デシリアライズの対象から除外します。
using System;
using Newtonsoft.Json;
public class Person
{
public string Name { get; set; }
[JsonIgnore]
public int Age { get; set; }
}
public class Program
{
public static void Main()
{
string jsonString = "{\"Name\":\"山田太郎\",\"Age\":30}";
Person person = JsonConvert.DeserializeObject<Person>(jsonString);
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}
}
Name: 山田太郎, Age: 0
Age
はJSONから無視され、デフォルト値の0
になります。
Required
[JsonRequired]
属性は、デシリアライズ時に必須のプロパティを指定します。
JSONに存在しない場合は例外が発生します。
using System;
using Newtonsoft.Json;
public class Person
{
[JsonRequired]
public string Name { get; set; }
public int Age { get; set; }
}
public class Program
{
public static void Main()
{
string jsonString = "{\"Age\":30}";
try
{
Person person = JsonConvert.DeserializeObject<Person>(jsonString);
}
catch (JsonSerializationException ex)
{
Console.WriteLine($"例外発生: {ex.Message}");
}
}
}
例外発生: Required property 'Name' not found in JSON. Path '', line 1, position 9.
必須項目のチェックに便利です。
カスタムJsonConverter
WriteJsonとReadJsonの実装手順
カスタム変換が必要な場合は、JsonConverter
を継承し、WriteJson
とReadJson
メソッドを実装します。
ReadJson
でJSONからオブジェクトへの変換、WriteJson
でオブジェクトからJSONへの変換を行います。
using System;
using Newtonsoft.Json;
public class StringToIntConverter : JsonConverter<int>
{
public override void WriteJson(JsonWriter writer, int value, JsonSerializer serializer)
{
// intを文字列として書き出す
writer.WriteValue(value.ToString());
}
public override int ReadJson(JsonReader reader, Type objectType, int existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.String)
{
string stringValue = (string)reader.Value;
if (int.TryParse(stringValue, out int result))
{
return result;
}
throw new JsonSerializationException("数値に変換できません");
}
else if (reader.TokenType == JsonToken.Integer)
{
return Convert.ToInt32(reader.Value);
}
throw new JsonSerializationException("不正なトークンタイプです");
}
public override bool CanRead => true;
public override bool CanWrite => true;
}
public class Person
{
public string Name { get; set; }
[JsonConverter(typeof(StringToIntConverter))]
public int Age { get; set; }
}
public class Program
{
public static void Main()
{
string jsonString = "{\"Name\":\"山田太郎\",\"Age\":\"30\"}";
Person person = JsonConvert.DeserializeObject<Person>(jsonString);
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}
}
Name: 山田太郎, Age: 30
ConverterAttributeでのバインド
カスタムコンバーターは、プロパティに[JsonConverter(typeof(ConverterType))]
属性を付けてバインドします。
これにより、そのプロパティのシリアライズ・デシリアライズ時にカスタム処理が適用されます。
高度なシナリオ
ポリモーフィック型の取り扱い
継承関係にあるクラスをJSONで扱う場合、基底クラスの型でデシリアライズすると派生クラスの情報が失われることがあります。
TypeNameHandling
を使うと、型情報をJSONに含めてポリモーフィックなデシリアライズが可能です。
using System;
using Newtonsoft.Json;
public abstract class Animal
{
public string Name { get; set; }
}
public class Dog : Animal
{
public string Breed { get; set; }
}
public class Program
{
public static void Main()
{
string jsonString = "{\"$type\":\"Dog\",\"Name\":\"ポチ\",\"Breed\":\"柴犬\"}";
var settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects
};
Animal animal = JsonConvert.DeserializeObject<Animal>(jsonString, settings);
if (animal is Dog dog)
{
Console.WriteLine($"Name: {dog.Name}, Breed: {dog.Breed}");
}
}
}
Name: ポチ, Breed: 柴犬
ExpandoObjectで動的解析
ExpandoObject
を使うと、JSONの構造が不定形でも動的にプロパティを扱えます。
using System;
using System.Dynamic;
using Newtonsoft.Json;
public class Program
{
public static void Main()
{
string jsonString = "{\"Name\":\"山田太郎\",\"Age\":30,\"Address\":{\"City\":\"東京\",\"Zip\":\"100-0001\"}}";
dynamic obj = JsonConvert.DeserializeObject<ExpandoObject>(jsonString);
Console.WriteLine($"Name: {obj.Name}, City: {obj.Address.City}");
}
}
Name: 山田太郎, City: 東京
LINQ to JSON(JObject, JToken)
JObject
やJToken
を使うと、JSONをツリー構造として扱い、柔軟に解析・操作できます。
using System;
using Newtonsoft.Json.Linq;
public class Program
{
public static void Main()
{
string jsonString = "{\"Name\":\"山田太郎\",\"Age\":30}";
JObject obj = JObject.Parse(jsonString);
string name = (string)obj["Name"];
int age = (int)obj["Age"];
Console.WriteLine($"Name: {name}, Age: {age}");
}
}
Name: 山田太郎, Age: 30
JObject
は部分的なJSONの読み書きや、動的なJSON操作に適しています。
ライブラリ選択のポイント
速度比較
JSONデシリアライズのパフォーマンスは、アプリケーションの応答性や処理効率に大きく影響します。
C#でよく使われるSystem.Text.Json
とNewtonsoft.Json
(Json.NET)を比較すると、一般的にSystem.Text.Json
の方が高速であることが多いです。
System.Text.Json
は.NET Core 3.0以降に標準搭載されており、低レベルのAPI設計やソースジェネレーション機能を活用することで、リフレクションを最小限に抑えた高速なシリアライズ・デシリアライズを実現しています。
特に大量のデータを扱う場合や高頻度でJSON処理を行うシステムでは、System.Text.Json
のパフォーマンス優位性が顕著です。
一方、Newtonsoft.Json
は多機能で柔軟性が高い反面、リフレクションを多用するため、処理速度はやや劣る傾向にあります。
ただし、複雑なJSON構造や特殊な変換が必要な場合は、Newtonsoft.Json
の機能がパフォーマンスよりも優先されることがあります。
速度比較のポイントをまとめると以下の通りです。
ライブラリ名 | 処理速度の特徴 | 備考 |
---|---|---|
System.Text.Json | 高速。ソースジェネレーションでさらに高速化可能 | .NET標準。軽量で高速処理に最適 |
Newtonsoft.Json | 柔軟だがやや遅い | 多機能で複雑なシナリオに強い |
実際の速度はJSONのサイズや構造、使用する機能によって変わるため、必要に応じてベンチマークを行うことが望ましいです。
機能の差異
System.Text.Json
とNewtonsoft.Json
はどちらもJSONのシリアライズ・デシリアライズを行えますが、機能面でいくつかの違いがあります。
- カスタムコンバーターの柔軟性
Newtonsoft.Json
はカスタムコンバーターの実装が柔軟で、複雑な変換ロジックやポリモーフィックな型の扱いに優れています。
System.Text.Json
もカスタムコンバーターをサポートしていますが、機能はやや限定的です。
- ポリモーフィック型のサポート
Newtonsoft.Json
はTypeNameHandling
を使って型情報をJSONに埋め込み、継承階層のオブジェクトを正しくデシリアライズできます。
System.Text.Json
は標準ではポリモーフィックなデシリアライズをサポートしていませんが、.NET 7以降で改善が進んでいます。
- LINQ to JSON
Newtonsoft.Json
はJObject
やJToken
を使った動的なJSON操作が可能で、部分的なJSON解析や編集に便利です。
System.Text.Json
はJsonDocument
やJsonElement
で類似の機能を提供しますが、APIの使い勝手や機能の豊富さではNewtonsoft.Json
に劣ります。
- 属性による制御
両者とも属性でプロパティ名のマッピングや無視設定が可能ですが、Newtonsoft.Json
の方が多彩な属性を提供しています。
- Unicodeエスケープの制御
System.Text.Json
はデフォルトで非ASCII文字をエスケープしますが、オプションで制御可能です。
Newtonsoft.Json
はデフォルトで日本語などのUnicode文字をエスケープしません。
- 非同期APIの充実度
System.Text.Json
は非同期のシリアライズ・デシリアライズAPIを標準で提供しています。
Newtonsoft.Json
は非同期APIが限定的です。
これらの違いを踏まえ、機能要件に応じて適切なライブラリを選択することが重要です。
互換性とサポート
- プラットフォーム対応
System.Text.Json
は.NET Core 3.0以降および.NET 5/6/7で標準搭載されており、クロスプラットフォーム対応が強化されています。
WindowsだけでなくLinuxやmacOSでも同じAPIが利用可能です。
Newtonsoft.Json
は.NET Frameworkから利用可能で、古い環境やレガシーシステムでも広く使われています。
NuGetパッケージとして提供されているため、ほぼすべての.NET環境で利用可能です。
- メンテナンスとアップデート
System.Text.Json
はMicrosoftが公式にメンテナンスしており、.NETのアップデートに合わせて機能強化やバグ修正が行われています。
Newtonsoft.Json
はJames Newton-King氏が開発・メンテナンスしているオープンソースプロジェクトで、活発に更新されていますが、.NET標準ライブラリではありません。
- コミュニティとドキュメント
Newtonsoft.Json
は長年の実績があり、豊富なドキュメントやサンプル、コミュニティの情報が充実しています。
System.Text.Json
は比較的新しいため、ドキュメントは増えつつありますが、まだNewtonsoft.Json
ほどの情報量はありません。
- 互換性の観点
既存のプロジェクトでNewtonsoft.Json
を使っている場合、移行には注意が必要です。
APIの違いや機能差異により、単純な置き換えが難しいケースがあります。
新規プロジェクトでは、標準ライブラリのSystem.Text.Json
を優先的に検討し、必要に応じてNewtonsoft.Json
を使うのが一般的です。
これらのポイントを踏まえ、プロジェクトの環境や要件に合わせて最適なJSONライブラリを選択してください。
共通のエラーハンドリング
例外タイプの解説
JSONのデシリアライズ処理では、さまざまな例外が発生する可能性があります。
代表的な例外タイプを理解しておくことで、適切なエラーハンドリングが可能になります。
System.Text.Jsonの例外
- JsonException
JSONの構文エラーや型不一致、無効なトークンなど、デシリアライズ時の一般的なエラーで発生します。
例えば、JSON文字列が不正な形式だったり、期待する型に変換できない場合にスローされます。
- NotSupportedException
サポートされていない型や機能を使った場合に発生します。
例えば、循環参照があるオブジェクトをデシリアライズしようとした場合などです。
- ArgumentNullException
入力のJSON文字列やストリームがnull
の場合に発生します。
Newtonsoft.Jsonの例外
- JsonReaderException
JSONの構文エラーがある場合に発生します。
読み込み中に不正なトークンや形式が検出されたときにスローされます。
- JsonSerializationException
JSONの内容が期待する型に合わない場合や、カスタムコンバーターでエラーが発生した場合にスローされます。
- ArgumentNullException
入力がnull
の場合に発生します。
これらの例外は、try-catchブロックで捕捉し、適切に処理することが重要です。
特にJsonException
やJsonSerializationException
は、ユーザーにわかりやすいエラーメッセージを返すためにキャッチしてログ出力や通知に活用します。
失敗を防ぐバリデーション
デシリアライズの失敗を未然に防ぐためには、入力データのバリデーションが効果的です。
以下のポイントを押さえておくと良いでしょう。
- JSONの構文チェック
事前にJSONの構文が正しいかを検証することで、無効なJSONによる例外を減らせます。
System.Text.Json
のJsonDocument.Parse
やNewtonsoft.Json
のJToken.Parse
を使って構文チェックが可能です。
- 必須プロパティの存在確認
JSONに必須のプロパティが含まれているかをチェックします。
Newtonsoft.Json
の[JsonRequired]
属性や、手動でJObject
を使った検証が有効です。
- 型の整合性チェック
期待する型と異なるデータが含まれていないかを確認します。
カスタムコンバーターでの変換時に例外を投げることで、異常値を検出できます。
- サイズ制限の設定
大量のデータや過剰に大きなJSONを受け取ると、メモリ不足やDoS攻撃のリスクがあります。
入力サイズを制限し、異常に大きい場合は処理を中断します。
- ホワイトリスト方式の検証
受け入れるプロパティ名や値の範囲を限定し、予期しないデータを排除します。
これらのバリデーションを組み合わせることで、デシリアライズの失敗や不正データの混入を防止できます。
ログ出力のベストプラクティス
エラー発生時のログ出力は、問題の原因特定や再発防止に不可欠です。
以下のポイントを意識してログを設計しましょう。
- 例外情報の詳細記録
例外の種類、メッセージ、スタックトレースを必ずログに含めます。
これにより、どの処理で何が原因で失敗したかを追跡しやすくなります。
- 入力データの一部記録
問題のJSONデータの一部(機密情報を除く)をログに残すことで、再現テストや解析が容易になります。
ただし、個人情報や機密情報はマスクや除外が必要です。
- ログレベルの適切な設定
エラーはError
レベル、警告はWarning
レベル、通常の情報はInformation
レベルで記録し、ログのノイズを減らします。
- ログの一貫性とフォーマット
ログメッセージは統一したフォーマットで記録し、検索や解析ツールで扱いやすくします。
JSON形式のログも有効です。
- 監視・通知との連携
重大なエラーは監視システムや通知ツールと連携し、即時対応できる体制を整えます。
- 例外の再スローやハンドリング
ログ出力後に例外を再スローするか、適切に処理してアプリケーションの安定性を保ちます。
以下はSystem.Text.Json
の例外をキャッチしてログ出力する例です。
using System;
using System.Text.Json;
public class Program
{
public static void Main()
{
string invalidJson = "{\"Name\":\"山田太郎\", \"Age\": \"三十\"}"; // Ageが文字列で不正
try
{
var person = JsonSerializer.Deserialize<Person>(invalidJson);
}
catch (JsonException ex)
{
Console.Error.WriteLine($"JSONデシリアライズエラー: {ex.Message}");
Console.Error.WriteLine($"スタックトレース: {ex.StackTrace}");
// ここでログファイルや監視システムに送信する処理を追加
}
}
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
このように、例外の詳細をログに残すことで、問題の早期発見と対応が可能になります。
セキュリティと安全性
改ざんされたJSONの対策
JSONデータはテキスト形式であるため、通信経路や保存先で改ざんされるリスクがあります。
改ざんされたJSONをそのままデシリアライズすると、アプリケーションの誤動作やセキュリティ上の脆弱性を招く恐れがあります。
以下の対策を講じることが重要です。
- デジタル署名の検証
JSONデータに対して署名を付与し、受信側で署名の検証を行うことで、改ざんの有無を判定できます。
HMACやRSA署名などの暗号技術を利用し、送信元の正当性とデータの完全性を保証します。
- TLS/SSLの利用
通信経路での改ざんを防ぐために、HTTPSなどの暗号化通信を必ず使用します。
これにより、中間者攻撃(MITM)によるデータ改ざんリスクを低減できます。
- JSONスキーマによる検証
JSONスキーマを用いて、受信したJSONが期待する構造や値の範囲に合致しているかを検証します。
スキーマ検証により、不正なデータや改ざんによる異常値を早期に検出可能です。
- ホワイトリスト方式の入力検証
受け入れるプロパティ名や値のパターンを限定し、予期しないデータを排除します。
これにより、改ざんによる不正なプロパティ追加や値の変更を防ぎます。
- 改ざん検知ログの記録
署名検証やスキーマ検証で異常が検出された場合は、詳細なログを残し、監視体制に連携して早期対応を促します。
これらの対策を組み合わせることで、改ざんされたJSONの影響を最小限に抑えられます。
外部入力に対するガード
外部から受け取るJSONは信頼できないデータとして扱い、以下のガードを設けることが安全性向上に繋がります。
- 入力サイズの制限
過剰に大きなJSONを受け取ると、メモリ不足や処理遅延を招きます。
最大サイズを設定し、超過した場合は処理を中断します。
- タイムアウト設定
デシリアライズ処理に時間制限を設け、長時間かかる処理を防止します。
これにより、リソースの枯渇を防ぎます。
- 型安全なデシリアライズ
期待する型に厳密にマッピングし、型の不一致や不正な型変換を防ぎます。
カスタムコンバーターでの検証も有効です。
- 例外処理の徹底
不正なJSONや予期しないデータで例外が発生した場合は、適切にキャッチして処理を中断し、システムの安定性を保ちます。
- ホワイトリスト検証
受け入れるプロパティや値の範囲を限定し、未知のプロパティや不正な値を拒否します。
- サニタイズ処理
JSON内の文字列データに対して、SQLインジェクションやクロスサイトスクリプティング(XSS)などの攻撃を防ぐためのサニタイズを行います。
これらのガードを実装することで、外部からの悪意ある入力による攻撃リスクを低減できます。
大容量データ解析時のDoS防止
大量のJSONデータを処理する際には、サービス拒否(DoS)攻撃やリソース枯渇のリスクがあります。
以下の対策を講じて安全に処理を行います。
- 入力サイズ制限の厳格化
受け入れるJSONの最大サイズを厳密に設定し、過大なデータは拒否します。
これにより、メモリやCPUの過剰消費を防ぎます。
- ストリーム処理の活用
一括でメモリに読み込むのではなく、System.Text.Json
のUtf8JsonReader
やNewtonsoft.Json
のJsonTextReader
などのストリームベースのAPIを使い、部分的にデータを処理します。
これによりメモリ使用量を抑制できます。
- タイムアウトとキャンセルトークン
処理時間に制限を設け、長時間の解析を中断できるようにします。
キャンセルトークンを利用して、外部から処理のキャンセルを可能にする設計も有効です。
- リソース監視とアラート
メモリ使用量やCPU負荷を監視し、閾値を超えた場合にアラートを発生させて早期対応を促します。
- 負荷分散とスケーリング
大量データ処理が必要な場合は、負荷分散やスケールアウトを検討し、一台のサーバーに負荷が集中しないようにします。
- 入力検証の強化
不要なデータや重複データを排除し、必要最小限のデータのみを処理するようにします。
これらの対策により、大容量JSONデータの解析時に発生しうるDoS攻撃やリソース枯渇を防止し、安定したサービス運用を実現します。
実運用で役立つTips
null許容参照型との併用
C# 8.0以降で導入されたnull許容参照型(Nullable Reference Types)は、参照型の変数がnullを許容するかどうかを明示的に示せる機能です。
JSONデシリアライズ時にnull許容参照型を活用すると、null値の扱いが明確になり、コードの安全性と可読性が向上します。
例えば、以下のようにstring?
型を使うと、Name
プロパティがnullを許容することを示せます。
using System;
using System.Text.Json;
public class Person
{
public string? Name { get; set; }
public int? Age { get; set; }
}
public class Program
{
public static void Main()
{
string jsonString = "{\"Name\":null,\"Age\":null}";
Person person = JsonSerializer.Deserialize<Person>(jsonString);
Console.WriteLine($"Name: {(person.Name ?? "null")}, Age: {(person.Age.HasValue ? person.Age.Value.ToString() : "null")}");
}
}
Name: null, Age: null
このように、null許容参照型を使うことで、JSONのnull値を安全に受け入れられます。
逆にnullを許容しない参照型にnullが入ると、コンパイル時に警告が出るため、バグの早期発見に役立ちます。
また、System.Text.Json
のJsonSerializerOptions
でDefaultIgnoreCondition
をJsonIgnoreCondition.WhenWritingNull
に設定すると、null値のプロパティをシリアライズ時に省略できます。
これと組み合わせると、より柔軟なnull値の扱いが可能です。
多言語環境でのエンコーディング
JSONはUTF-8を標準のエンコーディングとして想定していますが、多言語環境で日本語やその他の非ASCII文字を扱う際にはエンコーディング設定に注意が必要です。
System.Text.Json
はデフォルトでUTF-8エンコーディングを使用し、非ASCII文字は\uXXXX
形式でエスケープされます。
日本語などの文字をそのままJSONに含めたい場合は、JsonSerializerOptions
のEncoder
にJavaScriptEncoder.UnsafeRelaxedJsonEscaping
を指定します。
using System;
using System.Text.Json;
using System.Text.Encodings.Web;
public class Person
{
public string Name { get; set; }
}
public class Program
{
public static void Main()
{
var person = new Person { Name = "山田太郎" };
var options = new JsonSerializerOptions
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
WriteIndented = true
};
string jsonString = JsonSerializer.Serialize(person, options);
Console.WriteLine(jsonString);
}
}
{
"Name": "山田太郎"
}
Newtonsoft.Json
はデフォルトで日本語をエスケープせずに出力しますが、StringEscapeHandling
オプションで制御可能です。
また、JSONの読み込み時は、文字コードがUTF-8であることを前提に処理するのが一般的です。
外部から受け取るJSONが異なるエンコーディングの場合は、事前にUTF-8に変換してからデシリアライズすることが推奨されます。
レガシーAPIとの相互運用
既存のレガシーAPIやシステムとJSONデータをやり取りする場合、データ形式や仕様が異なることがあります。
相互運用性を確保するためのポイントを紹介します。
- プロパティ名のマッピング
レガシーAPIのJSONプロパティ名がC#の命名規則と異なる場合、[JsonPropertyName]
System.Text.Json
や[JsonProperty]
Newtonsoft.Json
属性でマッピングを行います。
- 日付・時刻のフォーマット調整
レガシーAPIがISO 8601以外の独自フォーマットを使う場合、カスタムコンバーターを実装して適切に変換します。
- null値や省略可能なプロパティの扱い
レガシーAPIがnullや省略をどのように扱うかを確認し、JsonSerializerOptions
やJsonSerializerSettings
で対応します。
- 型の不一致対応
数値が文字列で送られてくるなど、型の不一致がある場合はカスタムコンバーターで変換処理を追加します。
- バージョン管理
APIのバージョン違いによる仕様差異を考慮し、バージョンごとに異なるモデルクラスや変換ロジックを用意することも有効です。
- 例外処理の強化
レガシーAPIからの不正なJSONや予期しないデータに備え、例外処理を丁寧に実装し、ログを残すことが重要です。
これらの工夫により、レガシーAPIとのJSONデータのやり取りをスムーズに行い、システム全体の安定性と保守性を高められます。
参考コード集
最小構成のサンプル
JSONデシリアライズの基本を押さえた最小構成のサンプルコードです。
System.Text.Json
を使い、シンプルなクラスにJSON文字列をデシリアライズします。
using System;
using System.Text.Json;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
public class Program
{
public static void Main()
{
string jsonString = "{\"Name\":\"山田太郎\",\"Age\":30}";
Person person = JsonSerializer.Deserialize<Person>(jsonString);
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}
}
Name: 山田太郎, Age: 30
このコードは、JSON文字列をPerson
クラスに変換し、プロパティの値をコンソールに表示します。
最小限のコードでデシリアライズの流れを理解できます。
コマンドラインツールでの自動テスト
JSONデシリアライズの動作確認やテストをコマンドラインツールで自動化する例です。
引数でJSONファイルのパスを受け取り、デシリアライズして結果を表示します。
using System;
using System.IO;
using System.Text.Json;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
public class Program
{
public static int Main(string[] args)
{
if (args.Length == 0)
{
Console.Error.WriteLine("JSONファイルのパスを指定してください。");
return 1;
}
string filePath = args[0];
if (!File.Exists(filePath))
{
Console.Error.WriteLine($"ファイルが存在しません: {filePath}");
return 1;
}
try
{
string jsonString = File.ReadAllText(filePath);
Person person = JsonSerializer.Deserialize<Person>(jsonString);
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
return 0;
}
catch (JsonException ex)
{
Console.Error.WriteLine($"JSONデシリアライズエラー: {ex.Message}");
return 1;
}
catch (Exception ex)
{
Console.Error.WriteLine($"予期しないエラー: {ex.Message}");
return 1;
}
}
}
このツールは、JSONファイルの内容を読み込み、Person
オブジェクトに変換して表示します。
エラー時には標準エラー出力にメッセージを出し、終了コードで成功・失敗を判定可能です。
CI/CDパイプラインやバッチ処理の一部として利用できます。
Web APIクライアントでの利用
HTTPクライアントを使ってWeb APIからJSONレスポンスを取得し、デシリアライズする例です。
HttpClient
とSystem.Text.Json
を組み合わせて実装します。
using System;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
public class Program
{
public static async Task Main()
{
using var client = new HttpClient();
try
{
string url = "https://api.example.com/person/1";
HttpResponseMessage response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
string jsonString = await response.Content.ReadAsStringAsync();
Person person = JsonSerializer.Deserialize<Person>(jsonString);
Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}
catch (HttpRequestException ex)
{
Console.Error.WriteLine($"HTTPリクエストエラー: {ex.Message}");
}
catch (JsonException ex)
{
Console.Error.WriteLine($"JSONデシリアライズエラー: {ex.Message}");
}
}
}
Name: 山田太郎, Age: 30
このコードは、指定したURLからJSONデータを取得し、Person
クラスにデシリアライズして表示します。
非同期処理を使い、HTTP通信の失敗やJSONの不正に対して例外処理も行っています。
実際のAPIクライアント開発での基本パターンとして活用できます。
まとめ
この記事では、C#でJSONデシリアライズを行う際の基本から応用までを解説しました。
System.Text.Json
とNewtonsoft.Json
の使い方や特徴、パフォーマンスやセキュリティ面の注意点、実運用で役立つTipsも紹介しています。
適切なライブラリ選択やエラーハンドリング、カスタムコンバーターの活用により、安全かつ効率的にJSONデータを扱う方法が理解できます。
これにより、堅牢で保守性の高いアプリケーション開発に役立てられます。