.NET Core(C#): JsonSerializer実践オプションとコンバータ

業務アプリの開発を想定したJsonSerializerの使い方とサンプルです。

概要

業務想定のサンプル

  • 日本語(UTF8)の値の読み取り・書き込み
    UTF8形式のファイルをJSONにシリアライズする場合は良いのですが、JSONに出力するとUnicodeエスケープされてしまいます。(例えば、「あ」は「\u3042」のように出力される。)
    JsonSerializerOptions.Encoderでエスケープしない文字(範囲)を指定することで、日本語のUnicodeエスケープを抑制します。
  • 既定の日付書式の変更
    DateTime型の既定の日付書式は、”2020/11/22T03:23:45″, “2020/11/22T12:23:45+09:00″等のISO形式です。この書式は業務によって変わってくるので、カスタマイズできるようにします。詳細は後述します。
  • JSONフィールド名にキャメルケースを使用
    既定では、JSONに出力されるフィールド名はパスカルケースになります。例えば、MyNameプロパティは”MyName”というフィールド名で出力されます。経験的にキャメルケースのJSONを扱うことが多いので、ここではキャメルケース(“myName”)で出力されるように変更します。
  • コメントのスキップ
    既定ではJSONファイル上の”//”, “”のコメントはエラーになってしまいます。
    外部システムとのデータ交換では、処理効率が優先されるため、冗長なデータとなるコメントは使用されません。設定ファイルの定義や動作確認・テストのような場面では保守性や開発効率を向上できるため、コメントの使用を許容します。

変換のカスタマイズ

  • クラス・プロパティとJSONフィールドの変換はコンバータによって実現されています。
  • 標準で多様なコンバータが提供されています。
    • 一般的な型とJSONとの変換例をこちらに纏めてみました。
    • 標準のコンバータのソースコードはこちらで公開されています。
  • 標準のコンバータでは実現できない変換については、独自のコンバータを定義することもできます。
    以降では、典型的なコンバータのサンプルを説明します。
  • コンバータを使う方法以外にも、ファクトリーパターン(JsonConverterFactory)を使用する方法もありますが、こちらは別途説明予定です。

コンバータの使用方法

変換仕様を実装するためのコンバータの定義方法、定義したコンバータを特定の型やプロパティに指定する方法を説明します。

コンバータの定義方法

JsonConverterから派生したクラスを定義することでコンバータを作成できます。
例えば、bool型のtrue/falseをJSONに”yes”/”no”で出力する場合は、次のようにコンバータを定義します。

4行目のようにReadメソッドで「JSONから取得した文字列をどのように型に変換するか」を定義します。
逆に、6行目のようにWriteメソッドで「型の値をどのようにJSONに出力するか」を定義します。

コンバータの指定方法

定義したコンバータの指定方法は次の3つの方法があります。

  1. 特定の型に対する変換を変更したい場合(既定のコンバータの変更)
    JsonSerializerOptions.Convertersにコンバータを追加します。
  2. 特定プロパティの値を変換したい場合
    プロパティに[JsonConverter]を指定します。
  3. 特定クラスを変換したい場合(M:N変換、複雑な構造の変換時)
    クラス定義に[JsonConverter]を指定します。

bool型コンバータの例

bool型のtrue/falseを”yes”/”no”、”on”/”off”等の文字列に変換するコンバータの例を次に示します。
値の読み取り・書き込み等の共通の処理を基底クラスとして実装し、”yes”/”no”等の変換に使用する具体的な値を派生クラスで定義しています。

bool型のtrue/falseを1/0等の整数に変換するコンバータの例を次に示します。

DateTime型コンバータの例

DateTime型は既定で、”2020/11/22T03:23:45″, “2020/11/22T12:23:45+09:00″等のISO形式の日付書式になります。
私の経験的にISO形式は使用することは少なく、”2020/11/22 12:23:45″, “20201122”, “2020-06″等の業務独自の日付書式を使うことが多いため、このような日付書式を扱うコンバータの例を次に示します。

前述のコンバータ同様、値の読み取り・書き込み等の共通の処理を基底クラスとして実装し、日付書式を派生クラスで定義しています。

列挙型コンバータの例

列挙型の既定の出力)

既定では、列挙型は整数に変換されます。
例えば、次のStatus列挙型のプロパティの値がStartの場合、JSONファイルには1が出力さます。

列挙型の値名の出力

列挙型の整数ではなく、”Start”, “End”等の列挙型の値名で出力する場合は、既定のJsonStringEnumConverterを使用できます。
JsonStringEnumConverterのコンストラクタの引数指定でキャメルケース形式で値を出力することもできますが、これはJsonSerializerOptions.Convertersに追加する方法で指定する必要があります。(または独自のコンバータを作成するか。)

列挙型をカスタム値で出力

列挙型を独自の値に変換するコンバータの例を次に示します。
この例では、前述のStatus列挙型のStart/Endを、”begin”/”finish”に変換します。

クラスコンバータの例

URLのスキーム/ホスト名/ポート番号をプロパティとして持つクラスを、JSONのURIに変換するコンバータの例を次に示します。
(あくまでもサンプルであり、単純にURI型のプロパティを指定すれば、ほぼ同様のことができると思います。)