🚧 2020/02 追記: JSON の扱いに関するに新しい情報があります。
blog.beachside.dev
WebApiだったりAzure DocumentDBだったり色々と使っているJson.NET、新人さん向け内容の整理メモです。
> Environment
サンプルを書いた環境は以下です。
- Visual Studio 2015 (update2)
- NugetでNewtonsoft.Jsonをインストール
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にインスタンスをセットしてあげれば、スネークケースに対応するとかも簡単にできます。