WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

異種の要素を含む JSON 配列のデシリアライズ

by WebSurfer 2023年3月5日 13:14

JSON の配列で string, number, true/false, null, array, object など異種の要素が混ざったものを、デシリアライザに Newtonsoft.Json および System.Text.Json を使って .NET のオブジェクトに変換するとどうなるかを書きます。

デシリアライズ結果

上の画像の前者 result1.Data が Newtonsoft.Json を使った結果、後者 result2.Data が System.Text.Json を使った結果です。

Data は両方とも object[] 型で、その各要素も object 型ですが、その中身が違うところに注目してください。それがこの記事で書きたかったことです。

この例ほど多種の要素が混じっている配列というケースは実際にはないかもしれませんが、"NaN" という文字列と number ぐらいならあるかもしれません。なので、違いを覚えておくと役に立つかもしれないと思って備忘録として残しておくことにしました。

上の画像を表示するのに具体的のどのようにしたかを以下に書いておきます。

まず、元になる JSON 文字列ですが、以下の通りです。

{
  "Header": {
    "Id": 10,
    "Name": "Test Data"
  },
  "Data": [
    "NaN",
    -0.010565,
    true,
    10,
    1.02e2,
    null,
    [ "abc", "def", "ghi" ],
    { "Object": "test" }
  ]
}

Visual Studio の機能を使って上の JSON 文字列から C# のクラス定義を生成すると以下のようになります。やり方は先の記事「JSON 文字列から C# のクラス定義生成」を見てください。

public class Rootobject
{
    public Header Header { get; set; }
    public object[] Data { get; set; }
}

public class Header
{
    public int Id { get; set; }
    public string Name { get; set; }
}

"Data" は object[] 型にデシリアライズするという点に注目してください。

Newtonsoft.Json および System.Text.Json を使って JSON 文字列を上の C# のオブジェクトにデシリアライズします。コードは以下の通りです。ターゲットフレームワーク .NET 7.0 のコンソールアプリを使いました。

string filepath = @"C:\Users\...\json1.json";
string jsonString = "";
using (StreamReader sr = File.OpenText(filepath))
{
    jsonString = sr.ReadToEnd();
}

// Newtonsoft.Json
var result1 = Newtonsoft.Json.JsonConvert
              .DeserializeObject<Rootobject>(jsonString);

// System.Text.Json
var result2 = System.Text.Json.JsonSerializer
              .Deserialize<Rootobject>(jsonString);

上のコードを Visual Studio 2022 でデバッグ実行し、ブレークポイントで止めて変数 result1 と result2 の中身を表示したのがこの記事の一番上の画像です。

Tags: , ,

.NET Framework

コレクションを表現した JSON のデシリアライズ

by WebSurfer 2020年6月3日 15:49

以下のようなコレクション(配列)を表現した JSON 文字列を C# のオブジェクトにデシリアライズするときにハマった話を書きます。

こんなことにハマるのは無知だからだと言われそうですが、また無駄な時間を費やさないように備忘録として書いておくことにしました。

[
  {
    "id":1,
    "text":"project #1",
    "start_date":"2020-05-06",
    "end_date":"2020-05-26",
    "user":3,
    "duration":20,
    "parent":0,
    "progress":0
  },
  {
    "id":2,
    "text":"Task #1",
    "start_date":"2020-05-06",
    "end_date":"2020-05-16",
    "user":0,
    "duration":10,
    "parent":1,
    "progress":0
  },
  {
    "id":3,
    "text":"Task #2",
    "start_date":"2020-05-16",
    "end_date":"2020-05-26",
    "user":0,
    "duration":10,
    "parent":1,
    "progress":0
  }
]

先の記事「JSON 文字列から C# のクラス定義生成」で書きましたように、Visual Studio を使って JSON 文字列から C# のオブジェクトのクラス定義を生成することができます。

上の JSON 文字列から Visual Studio で C# のクラス定義を生成すると以下の通りとなります。

public class Rootobject
{
    public Class1[] Property1 { get; set; }
}

public class Class1
{
    public int id { get; set; }
    public string text { get; set; }
    public string start_date { get; set; }
    public string end_date { get; set; }
    public int user { get; set; }
    public int duration { get; set; }
    public int parent { get; set; }
    public int progress { get; set; }
}

Newtonsoft.Json と JavaScriptSerializer で上に書いた JSON 文字列を Rootobject にデシリアライズしてみます。コード例は以下の通りです。

// Newtonsoft.Json
var result1 = JsonConvert.DeserializeObject<Rootobject>(jsonText);

// JavaScriptSerializer
var serializer = new JavaScriptSerializer();
var result2 = serializer.Deserialize<Rootobject>(jsonText);

そうすると、Newtonsoft.Json では JsonSerializationException 例外が、JavaScriptSerializer では InvalidOperationException 例外がスローされます。Newtonsoft.Json が表示するエラーメッセージは以下の通りでした。

Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'ConsoleAppJson.Rootobject' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly. To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array. Path '', line 1, position 1.'

これによると Rootobject ではダメで、List<Class1> にデシリアライズしろということのようです。やってみたら確かに List<Class1> にはデシリアライズできました。

なお、上のような配列だけの JSON 文字列ではなくて、例えば { "data": [ { ... },{ ... },{ ... } ] } のような形の JSON 文字列にした場合は、Visual Studio により生成される C# のクラス定義はほぼ同じになりますが、Rootobject にデシリアライズできます。

[ { ... },{ ... },{ ... } ] という形の JSON 文字列だけが要注意のようです。

.NET Framework 版の ASP.NET MVC は JavaScriptSerializer を、ASP.NET Web API は Newtonsoft.Json を使っているので、上のような JSON 文字列を送信してアクションメソッドに渡す場合が自分的に要注意だと思いました。

Tags: , ,

.NET Framework

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年4月  >>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar