ファイル

【C#】System.Text.JsonとNewtonsoft.Jsonで学ぶJSONデシリアライズの基本と実践テクニック

C#でJSONを扱うにはSystem.Text.JsonNewtonsoft.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.JsonNewtonsoft.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.JsonMicrosoft (.NET).NET Core 3.0以降の標準ライブラリ。高速で軽量、標準機能が充実。Unicodeエスケープの制御など細かい設定も可能です。
Newtonsoft.Json (Json.NET)サードパーティ長年使われている実績豊富なライブラリ。柔軟な設定や拡張性が高く、複雑なシナリオに対応しやすい。
DataContractJsonSerializerMicrosoft (.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.JsonNewtonsoft.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#のプロパティ名の大文字・小文字が異なる場合でもマッチさせたいときに使います。

デフォルトでは大文字・小文字を区別するため、PropertyNameCaseInsensitivetrueに設定します。

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のnameageNameAgeに正しくマッピングされます。

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値の扱いを制御したい場合に使います。

DefaultIgnoreConditionJsonIgnoreCondition.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が存在しなくてもエラーにならず、Agenullとして扱われます。

属性による制御

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_nameNameプロパティに正しくマッピングされます。

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>を継承し、ReadWriteメソッドをオーバーライドして変換処理を実装します。

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の構造が固定されていない場合、JsonDocumentJsonElementを使って動的に解析します。

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

この例では、Nicknamenullでも無視されるため、既存の値が保持されます。

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

Age0(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_nameNameにマッピングされ、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を継承し、WriteJsonReadJsonメソッドを実装します。

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)

JObjectJTokenを使うと、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.JsonNewtonsoft.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.JsonNewtonsoft.JsonはどちらもJSONのシリアライズ・デシリアライズを行えますが、機能面でいくつかの違いがあります。

  • カスタムコンバーターの柔軟性

Newtonsoft.Jsonはカスタムコンバーターの実装が柔軟で、複雑な変換ロジックやポリモーフィックな型の扱いに優れています。

System.Text.Jsonもカスタムコンバーターをサポートしていますが、機能はやや限定的です。

  • ポリモーフィック型のサポート

Newtonsoft.JsonTypeNameHandlingを使って型情報をJSONに埋め込み、継承階層のオブジェクトを正しくデシリアライズできます。

System.Text.Jsonは標準ではポリモーフィックなデシリアライズをサポートしていませんが、.NET 7以降で改善が進んでいます。

  • LINQ to JSON

Newtonsoft.JsonJObjectJTokenを使った動的なJSON操作が可能で、部分的なJSON解析や編集に便利です。

System.Text.JsonJsonDocumentJsonElementで類似の機能を提供しますが、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ブロックで捕捉し、適切に処理することが重要です。

特にJsonExceptionJsonSerializationExceptionは、ユーザーにわかりやすいエラーメッセージを返すためにキャッチしてログ出力や通知に活用します。

失敗を防ぐバリデーション

デシリアライズの失敗を未然に防ぐためには、入力データのバリデーションが効果的です。

以下のポイントを押さえておくと良いでしょう。

  • JSONの構文チェック

事前にJSONの構文が正しいかを検証することで、無効なJSONによる例外を減らせます。

System.Text.JsonJsonDocument.ParseNewtonsoft.JsonJToken.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.JsonUtf8JsonReaderNewtonsoft.JsonJsonTextReaderなどのストリームベースの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.JsonJsonSerializerOptionsDefaultIgnoreConditionJsonIgnoreCondition.WhenWritingNullに設定すると、null値のプロパティをシリアライズ時に省略できます。

これと組み合わせると、より柔軟なnull値の扱いが可能です。

多言語環境でのエンコーディング

JSONはUTF-8を標準のエンコーディングとして想定していますが、多言語環境で日本語やその他の非ASCII文字を扱う際にはエンコーディング設定に注意が必要です。

System.Text.JsonはデフォルトでUTF-8エンコーディングを使用し、非ASCII文字は\uXXXX形式でエスケープされます。

日本語などの文字をそのままJSONに含めたい場合は、JsonSerializerOptionsEncoderJavaScriptEncoder.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や省略をどのように扱うかを確認し、JsonSerializerOptionsJsonSerializerSettingsで対応します。

  • 型の不一致対応

数値が文字列で送られてくるなど、型の不一致がある場合はカスタムコンバーターで変換処理を追加します。

  • バージョン管理

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レスポンスを取得し、デシリアライズする例です。

HttpClientSystem.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.JsonNewtonsoft.Jsonの使い方や特徴、パフォーマンスやセキュリティ面の注意点、実運用で役立つTipsも紹介しています。

適切なライブラリ選択やエラーハンドリング、カスタムコンバーターの活用により、安全かつ効率的にJSONデータを扱う方法が理解できます。

これにより、堅牢で保守性の高いアプリケーション開発に役立てられます。

関連記事

Back to top button
目次へ