BEACHSIDE BLOG

MicrosoftとかC#を好むレンジャーの個人的メモ

C# Json.NET 入門1:JsonConvert

WebApiだったりAzure DocumentDBだったり色々と使っているJson.NET、新人さん向け内容の整理メモです。

f:id:beachside:20160415200847j:plain

> Environment

サンプルを書いた環境は以下です。

Newtonsoft.Jsonは、2016/4時点で最新の8.0.3を使っています。

> Overview

C# Json.net 入門1:JsonConvert (今回)

C# Json.net 入門2:JsonSerializerSettings(次回)

  • 1. Formatting
  • 2. NullValueHandling
  • 3. MissingMemberHandling
  • その他

C# Json.net 入門3 動的なRootNameのJsonをデシリアライズ


  
C#でコンソールアプリを作り、サンプルのクラスをコネコネしてみます。
Newtonsoft.Jsonのインストールは、Visual Studioの上部のメニューから
[ツール] > [Nuget パッケージマネージャー] > [パッケージマネージャーコンソール]
でコンソールを開き、以下のコマンドを実行すると最新安定板がサクッとインストールされます。

 install-package newtonsoft.json

コンソールアプリには、modelとなる以下のクラスとして以下を用意してみました。

1. JsonConvertでサクッとシリアライズ・デシリアライズ

シリアライズ・デシリアライズをする方法には、大きく2通りあります。

  • JsonConvertを使って処理
  • JsonSerializerを使って処理

Serializing and Deserializing JSON

JsonConvertを使って簡易に処理を実装することが可能です。
JsonSerializerを使うと、より柔軟に色々な処理ができます。例として大容量のjsonを処理する際には、パフォーマンス等を考慮してJsonSerializerを使うことが考えられます。

今回は、サクッとできるJsonConvertの話になります。

以下のサンプルでは、Personクラスのインスタンスjson形式のstringへコンバート(20行目と24行目)、そしてそのstringをPersonクラスにデシリアライズ(28行目)しています。

インデントつけて出力された結果をみるとこーなりました。

{
  "FirstName": "shinobu",
  "LastName": "oshino",
  "Age": 598,
  "Favorites": [
    "golden chocolate",
    "pon de ring"
  ],
  "Phones": [
    {
      "PhoneNumber": "000-000-111",
      "ModelName": "Lumia"
    },
    {
      "PhoneNumber": "111-000-000",
      "ModelName": "Nokia"
    }
  ],
  "FullName": "shinobu oshino"
}

C#のクラスのプロパティ名がパスカルケースに対して、jsonはキャメルケースが一般的なので、これだけだとあまり実用的ではないかもと感じます。

2. プロパティ名をキャメルケースで出力

これを解消する簡易な方法を2通り書きます。

  • Attribute
  • JsonSerializerSettings

どちらでもやりたいほうでやればいいと思います。たまにパフォーマンスの問題が出るかもしれませんので、そこはケースバイケースで。

Attributeを利用

Attributeの詳細は本家で見ていただくとして。
http://www.newtonsoft.com/json/help/html/serializationattributes.htm

[Person]クラスの各プロパティで、JsonPropertyのPropertyNameを指定することで対応できます。
ついでに、「[FullName]プロパティはjsonに出力しない」という勝手なルールを決め、[JsonIgnore]Attributeをつけてjsonで出力しないように設定しました。

参考までに複数のAttributeを一行で書くこともできます。

[JsonProperty(PropertyName = "fullName"), JsonIgnore]

これで「JsonConvert.SerializeObject」メソッドを処理をすると、プロパティ名がキャメルケースとして出力されます。

{
  "firstName": "shinobu",
  "lastName": "oshino",
  "age": 598,
  "favorites": [
    "golden chocolate",
    "pon de ring"
  ],
  "phones": [
    {
      "phoneNumber": "000-000-111",
      "modelName": "Lumia"
    },
    {
      "phoneNumber": "111-000-000",
      "modelName": "Nokia"
    }
  ]
}

Attributeでよく使うのは、この2つくらいかなーとか思ってます。

JsonSerializerSettingsで対応

JsonSerializerSettingsは、色々と設定ができます。
JsonSerializerSettings Class

今回は、キャメルケースの件にとどめ、次回においしそうなところを整理します。

JsonConvert.SerializeObjectのメソッドで、以下のようにJsonSerializerSettingsを引数として渡してあげます。

これで、[Person]クラスにAttributeをつけなくても、キャメルケースとして出力されます。

余談:スーパークラス化、スネークケース

スーパークラスを作って...

キャメルケースの対応は、ASP.NET MVC5なら、あんなとここんなとこで設定したり、ASP.NET Core1.0 (旧ASP.NET5)ならStartup.csで設定したりできます。

ただ、modelを定義しているレイヤーを別アセンブリにしてASP.NET以外からも使ってると、ASP.NETで定義するだけでは適用しきれないため、jsonに出力する際のその他諸々のbehaviorも含め、modelの責務を持たせたいときってあります(よね)。
そんなときは、スーパークラス作ってみたり。

[ToJsonString()]メソッドを作らなくても、[ToString()]をオーバーライドしてもどっちでもいいと思います(リーダブルに欠けそうなので私はやらないですが)。

その他のbehaviorもあったらここに書いて、責務を持たせてあげると色々すっきりすると(個人的には)思ってます。
インデントほしいときは、それもここでメソッド作ってあげればいいですね。

では、Personクラスに継承させましょ。

public class Person : JsonSerializable

これで、クラスをjsonにするときは、スッキリします。

スネークケース

以下のようなContractResolverを自分でつくって、JsonSerializerSettingsのContractResolverにインスタンスをセットしてあげれば、スネークケースに対応するとかも簡単にできます。