Newtonsoft.Json

シリアライゼーション.NETJSONC#データバインディングカスタマイズ

ライブラリ

Newtonsoft.Json

概要

Newtonsoft.Json(Json.NET)は、60億ダウンロードを誇る.NET JSONライブラリの定番です。豊富な機能とカスタマイズ性により複雑なオブジェクトグラフも処理可能で、長年にわたり.NETエコシステムの標準として信頼されてきました。LINQ to JSON、カスタムコンバーター、エラーハンドリング、日付形式処理など、エンタープライズ級の包括的なJSON処理機能を提供し、複雑なカスタマイズが必要なアプリケーションに最適な選択肢として重要な地位を保持しています。

詳細

Newtonsoft.Json 13.0.3は、既存の.NETアプリケーションで広く使用され続けている成熟したライブラリです。新規プロジェクトではSystem.Text.Jsonへの移行が推奨されていますが、複雑なカスタマイズやレガシーコードとの互換性、高度なスキーマ検証機能が必要な場合には依然として重要な選択肢です。JsonConvert静的クラスによる簡単なAPI、JsonSerializer によるストリーミング、JObject/JArray/JTokenによるLINQ to JSON、豊富なカスタムアトリビュート、プロパティ名変換規則など、多岐にわたる機能を提供します。

主な特徴

  • 豊富なカスタマイズオプション: カスタムコンバーター、命名規則、日付形式等
  • LINQ to JSON: JObject、JArray、JTokenによる動的JSON操作
  • 高度なエラーハンドリング: 詳細なエラー情報と柔軟な処理
  • 包括的なアトリビュート: JsonProperty、JsonIgnore、JsonConverter等
  • 多様な設定: DefaultValueHandling、NullValueHandling等の細かな制御
  • スキーマ検証: JSON Schemaによるバリデーション機能

メリット・デメリット

メリット

  • 10年以上の開発実績による高い安定性と信頼性
  • 豊富なカスタマイズ機能と柔軟な設定オプション
  • LINQ to JSONによる動的なJSON操作とクエリ機能
  • 複雑なオブジェクトグラフとサイクリック参照の処理
  • 詳細なドキュメントと豊富なコミュニティリソース
  • JSON Schema検証とカスタムコンバーターサポート

デメリット

  • System.Text.Jsonと比較して性能が劣り、メモリ使用量が多い
  • リフレクションベースの実装によるパフォーマンスオーバーヘッド
  • .NET Core/.NET 5+では標準ライブラリではなく外部依存関係
  • 一部のAPIが複雑で学習コストが高い
  • AOT(Ahead-of-Time)コンパイルとの互換性が限定的
  • 大きなファイルサイズと起動時間への影響

参考ページ

書き方の例

基本的なセットアップ

<!-- .csproj ファイル -->
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

// 基本的なシリアライゼーション
var product = new Product { Name = "Apple", Price = 1.99m };
string json = JsonConvert.SerializeObject(product);

// 基本的なデシリアライゼーション
var deserializedProduct = JsonConvert.DeserializeObject<Product>(json);

高度な設定とカスタマイズ

// カスタムシリアライゼーション設定
var settings = new JsonSerializerSettings
{
    DateFormatHandling = DateFormatHandling.IsoDateFormat,
    NullValueHandling = NullValueHandling.Ignore,
    DefaultValueHandling = DefaultValueHandling.Ignore,
    Formatting = Formatting.Indented,
    ContractResolver = new CamelCasePropertyNamesContractResolver()
};

string json = JsonConvert.SerializeObject(data, settings);

// カスタムコンバーター使用
public class CustomDateTimeConverter : JsonConverter<DateTime>
{
    public override void WriteJson(JsonWriter writer, DateTime value, JsonSerializer serializer)
    {
        writer.WriteValue(value.ToString("yyyy-MM-dd HH:mm:ss"));
    }

    public override DateTime ReadJson(JsonReader reader, Type objectType, DateTime existingValue, 
        bool hasExistingValue, JsonSerializer serializer)
    {
        return DateTime.ParseExact((string)reader.Value, "yyyy-MM-dd HH:mm:ss", null);
    }
}

LINQ to JSON操作

// JObjectによる動的JSON操作
var jObject = new JObject
{
    ["name"] = "Product Name",
    ["price"] = 29.99,
    ["categories"] = new JArray("electronics", "gadgets"),
    ["specifications"] = new JObject
    {
        ["weight"] = "500g",
        ["dimensions"] = "10x5x2 cm"
    }
};

// JSON文字列に変換
string json = jObject.ToString();

// JObjectからのデータ取得
string name = (string)jObject["name"];
decimal price = (decimal)jObject["price"];
var categories = jObject["categories"].ToObject<string[]>();

// LINQクエリによる検索
var expensiveProducts = jObject
    .Where(p => (decimal)p["price"] > 20)
    .Select(p => p["name"])
    .ToList();

パフォーマンス最適化

// JsonSerializerを使用したストリーミング
using (var stringWriter = new StringWriter())
using (var jsonWriter = new JsonTextWriter(stringWriter))
{
    var serializer = new JsonSerializer();
    serializer.Serialize(jsonWriter, largeDataObject);
    string json = stringWriter.ToString();
}

// 非同期デシリアライゼーション
public async Task<T> DeserializeAsync<T>(Stream stream)
{
    using (var reader = new StreamReader(stream))
    using (var jsonReader = new JsonTextReader(reader))
    {
        var serializer = new JsonSerializer();
        return await Task.Run(() => serializer.Deserialize<T>(jsonReader));
    }
}

// パフォーマンス設定
var settings = new JsonSerializerSettings
{
    MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
    DateParseHandling = DateParseHandling.None,
    FloatParseHandling = FloatParseHandling.Decimal
};

エラーハンドリングと検証

// エラーハンドリング設定
var settings = new JsonSerializerSettings
{
    Error = (sender, args) =>
    {
        Console.WriteLine($"Error: {args.ErrorContext.Error.Message}");
        args.ErrorContext.Handled = true;
    },
    MissingMemberHandling = MissingMemberHandling.Error
};

try
{
    var result = JsonConvert.DeserializeObject<Product>(json, settings);
}
catch (JsonException ex)
{
    Console.WriteLine($"JSON解析エラー: {ex.Message}");
}

// 条件付きシリアライゼーション
public class Product
{
    public string Name { get; set; }
    
    [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
    public decimal? Price { get; set; }
    
    [JsonIgnore]
    public string InternalId { get; set; }
    
    public bool ShouldSerializePrice()
    {
        return Price.HasValue && Price > 0;
    }
}

ASP.NET Coreとの統合

// Startup.cs または Program.cs
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
        .AddNewtonsoftJson(options =>
        {
            options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            options.SerializerSettings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
            options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
        });
}

// APIコントローラーでの使用
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    [HttpPost]
    public IActionResult CreateProduct([FromBody] Product product)
    {
        // Newtonsoft.Jsonによる自動デシリアライゼーション
        return Ok(new { Success = true, Product = product });
    }
}

// カスタムレスポンス形式
public class ApiResponse<T>
{
    [JsonProperty("data")]
    public T Data { get; set; }
    
    [JsonProperty("success")]
    public bool Success { get; set; }
    
    [JsonProperty("message")]
    public string Message { get; set; }
    
    [JsonProperty("timestamp")]
    public DateTime Timestamp { get; set; } = DateTime.UtcNow;
}

レガシーシステムとの統合

// 複雑なマッピングとカスタマイズ
public class LegacySystemAdapter
{
    private readonly JsonSerializerSettings _settings;
    
    public LegacySystemAdapter()
    {
        _settings = new JsonSerializerSettings
        {
            ContractResolver = new DefaultContractResolver
            {
                NamingStrategy = new SnakeCaseNamingStrategy()
            },
            Converters = { new LegacyDateTimeConverter(), new LegacyBooleanConverter() },
            TypeNameHandling = TypeNameHandling.Auto
        };
    }
    
    public string SerializeForLegacySystem<T>(T data)
    {
        return JsonConvert.SerializeObject(data, _settings);
    }
    
    public T DeserializeFromLegacySystem<T>(string json)
    {
        return JsonConvert.DeserializeObject<T>(json, _settings);
    }
}

// 複雑な型変換
public class LegacyDateTimeConverter : JsonConverter<DateTime>
{
    public override void WriteJson(JsonWriter writer, DateTime value, JsonSerializer serializer)
    {
        // レガシーシステム用の特殊な日付形式
        writer.WriteValue(value.ToString("yyyyMMddHHmmss"));
    }
    
    public override DateTime ReadJson(JsonReader reader, Type objectType, DateTime existingValue,
        bool hasExistingValue, JsonSerializer serializer)
    {
        var dateString = (string)reader.Value;
        return DateTime.ParseExact(dateString, "yyyyMMddHHmmss", null);
    }
}