C#:Text.Jsonのシリアライズ・デシリアライズ

C# Web

今回はText.Jsonを使った
JSONのシリアライズとデシリアライズについてです。

.net core になってからマイクロソフトが Text.Jsonを押すようになったそうです。

ただ、以前流行っていたNewtonsoft.Json に比べ圧倒的に 記事が少ない。。。
という訳で、Text.Jsonを使ったシリアライズ・デシリアライズについて書いていきます。

あと。事前にusingに以下を追加してください。


using System.Text.Json;
using System.Text.Json.Serialization;

スポンサードサーチ

デシリアライズ 基本編

まず、デシリアライズの場合を考えてみます。
違和感がありますが、デシリアライズから解説していきます。
JSON => オブジェクト(クラス) がデシリアライズですね。

例えば、APIを通じでデータを取得した時、それをJSONで受けたとしましょう。
そのときにJSONのデータを、既存のクラスに落とし込みたいですよね。
その操作をデシリアライズと言います。

APIで取得したとき、その中身が以下のような形だったとします。


// APIで取得したJSONデータ
{
    "userType": "Member",
    "extension_08facba522fc43548d914d5c3be5ed92_customerCode": 1111
}"

この場合、Memberという値を取りたいとします。
対応するクラスをUserクラスとして、そのプロパティに対して、


// デシリアライズ時に、userTypeのキーをUserTypeのプロパティに入れる
// Userクラスが持つプロパティ
[JsonPropertyName("userType")]
public string UserType { get; set; }

と定義しておけばOKです。JSONに『userType』というキーがあれば、勝手にデシリアライズしてくれます。

そして渡ってきたJSONデータの2行目の
extension_08facba522fc43548d914d5c3be5ed92_customerCode
という複雑そうなキーも、事前に分かる場合は


// 複雑そうなキーでもこんな風に書けばOK
[JsonPropertyName("extension_08facba522fc43548d914d5c3be5ed92_customerCode")]
public int customerCode { get; set; }

と書けばOKです。

そして最後に、JsonSerializer.Deserialize(_json)で、デシリアライズします。


// これででデシリアライズできる
var user = JsonSerializer.Deserialize(_json);

// _jsonの中身はこれ
{
    "userType": "Member",
    "extension_08facba522fc43548d914d5c3be5ed92_customerCode": 1111
}"

このようにデシリアライズしましょう。
これでオブジェクトとして取得できます。

デシリアライズ 困った編

次に少し困ったケースを考えてみましょう。
先程出てきた2行目の
『extension_08facba522fc43548d914d5c3be5ed92_customerCode』という複雑なキーに注目します。

例えば、この『08facba522fc43548d914d5c3be5ed92』の部分が事前に分からなかったとしましょう。
このキーを変数Idとして、キーを作ると考えます。つまり、


// 変数Id に後から『08facba522fc43548d914d5c3be5ed92』という値が入る予定
[JsonPropertyName($"extension_{Id}_customerCode")]
public int customerCode { get; set; }

という感じで書きたいですよね。ですが、属性([JsonPropertyName(“…”)]の部分)に変数が入ってしまうと、ビルドの際に怒られてしまいます。

これではデシリアライズできません。困りましたね。

スポンサードサーチ

デシリアライズ 解決編

そこで、
デシリアライズするクラスに、以下のようなプロパティを一つ加えましょう。


[JsonExtensionData]
public Dictionary ExtensionData { get; set; }
 // or Dictionary


このJsonExtensionDataの属性であるExtensionDataに
デシリアライズしきれなかった分のキーと値が入ってきます。

値を取りたいときは、メソッドを通じでキーを渡して取得するようにします。


// クラスのメソッドとして定義しておく
public int GetCustomerCode( string id ) {
    return int.Parse(ExtensionData[$"extension_{id}_customerCode"].ToString());
}

やっていることは簡単で、ExtensionDataに入っているディクショナリーデータから、一致するキーを取るというものです。
これでIdが動的に変わる場合もデシリアライズできます。

getter のようにしても良いのかもしれませんが、渡ってきたJSONデータのキーと同じ名前であるとハマってしまいます。そのあたりは気を付けましょう。
私はメソッドを定義して取得する方を推奨します。

シリアライズは?

シリアライズは、
オブジェクト(クラス) => JSONにする事です。

オブジェクトをそっくりそのまま対応したJSONデータに変換してほしいときがあります。
例えば、APIでPOSTする時ですね。
APIで用意されている仕様に合わせたクラスを作り、そのオブジェクトをJSONに直し、POSTするというケースです。

まずは、キーが静的(事前に決まっている場合)であるときを考えましょう。


public class Uer {

    [JsonPropertyName("userType")]
    public string UserType { get; set; }

    [JsonPropertyName("extension_08facba522fc43548d914d5c3be5ed92_customerCode")]
    public int CustomerCode { get; set; }
}

というクラスがあった時、オブジェクトがuserだとします。
その時のシリアライズ方法は、


// userがUserクラスのオブジェクト
// myJsonにはJSONデータが入ってくる
var myJson = JsonSerializer.Serialize(user);

です。これで充分でしょう。JsonPropertyNameで勝手に変換してくれます。

スポンサードサーチ

シリアライズ 動的に行う時

デシリアライズの場合と同様に、静的でない時を考えましょう。

結果だけ言ってしまえば、ExtensionDataにぶち込みます。
ただ、APIからデシリアライズしたオブジェクトを、再度シリアライズするのはやめましょう。
ExtensionDataに不要なデータも入っていることがあります。
『デシリアライズしたオブジェクト丸ごとを使わなければならないとき』以外はやめた方がいいです。

私が推奨する方法は、送信用のクラス作り、そのオブジェクトにデータを入れましょう
そうすれば、不要なExtensionDataはありません。

動的なキーのデータを追加するときは、


// 値をExtensionDataに追加する
public void SetCustomerCode( string id, int customerCode ) {
    // この処理は別でやっておいてもよい
       ExtensionData = new Dictionary();
       
    // キーを作成
    var key = $"extension_{id}_customerCode";

    // 追加(キーと値)
       ExtensionData.Add(key, customerCode);
}

SetCustomerCodeを呼び出して、id(キー)とcustoemerCode(値)を入れます。
そのあとにシリアライズすれば、シリアライズの際にExtensionDataの中身も見てJSONデータを作ってくれます。
結構便利な機能です。

まとめ

  • 内容:Text.JSONのシリアライズとデシリアライズ
  • 大事なところ:
    JsonExtensionDataにデシリアライズできなかったデータが入る。
    動的なプロパティのシリアライズのときは、JsonExtensionDataのディクショナリーに追加してやるといい。

という感じです。
最初も言った通り、Text.Jsonの記事が少ないです。
参考になれば幸いです。