デシリアライズするタイプが常にわかっているとは限りません。したがって、任意のJSON(配列を含む)を取得し、そこから動的にテーブルを生成できると便利です。
ただし、デシリアライザーが集計する配列を探す場所がわからない場合は、問題が発生する可能性があります。これが発生すると、次のようなエラーメッセージが表示されます。
DataTableの読み取り時に予期しないJSONトークン。StartArrayが必要で、StartObjectを取得しました。パス''、行1、位置1。
励ましを与えたり、それに応じてjsonを準備したりしても、配列内の「オブジェクト」タイプは、デシリアライザーが行などでオブジェクトを表す方法を知らない場合でも、集計の発生を防ぐことができます。この場合、次のようなエラーが発生します。
DataTable:StartObjectを読み取るときに予期しないJSONトークン。パス'[0].__ metadata'、行3、位置19。
以下のJSONの例には、これらの問題のある機能の両方が含まれています。
{
"results":
[
{
"Enabled": true,
"Id": 106,
"Name": "item 1",
},
{
"Enabled": false,
"Id": 107,
"Name": "item 2",
"__metadata": { "Id": 4013 }
}
]
}
では、どうすればこれを解決し、それでも、非リアル化するタイプがわからないという柔軟性を維持できるでしょうか。
これが私が思いついた簡単なアプローチです(上記の例の__metadataなどのオブジェクトタイプのプロパティを無視しても問題ないと仮定します)。
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Data;
using System.Linq;
...
public static DataTable Tabulate(string json)
{
var jsonLinq = JObject.Parse(json);
// Find the first array using Linq
var srcArray = jsonLinq.Descendants().Where(d => d is JArray).First();
var trgArray = new JArray();
foreach (JObject row in srcArray.Children<JObject>())
{
var cleanRow = new JObject();
foreach (JProperty column in row.Properties())
{
// Only include JValue types
if (column.Value is JValue)
{
cleanRow.Add(column.Name, column.Value);
}
}
trgArray.Add(cleanRow);
}
return JsonConvert.DeserializeObject<DataTable>(trgArray.ToString());
}
これはもっと「LINQy」であり、例外処理がまったくないことを私は知っていますが、うまくいけば、概念が伝えられます。
私たちは仕事でJSONを吐き出すサービスをますます使用し始めているので、私は怠惰なので、すべてを強く入力することから解放されることが私の明らかな好みです!