如何在JSON中为空DataTable包含列元数据

如何在JSON中正确描述列元数据,稍后由Newtonsoft解析以构建ac#DataTable,这样我希望解决获取没有行的DataTable但没有列的问题,我需要列到当我传递一个空表时,使用标签创建并希望使用数据类型。

标准输入的示例:

{ "BrokerID" : "998", "AccountID" : "1313", "Packages":[ { "PackageID": 226, "Amount": 15000, "Auto_sync": true, "Color": "BLUE" }, { "PackageID": 500, "Amount": 15000, "Auto_sync": true, "Color": "PEACH" } ] } 

输入空表的示例:{“BrokerID”:“998”,“AccountID”:“1313”,“包”:[]}

当我使用JsonConvert.DeserializeObject(params["Packages"]);解析时JsonConvert.DeserializeObject(params["Packages"]); 我没有行,显然没有列,我正在寻找一种方法来描述json体内的列元数据。

即使您将TypeNameHandling设置为All ,Json.Net附带的DataTableConverter也不会输出列元数据。 但是,没有什么可以阻止您制作自己的自定义转换器来执行此操作,而是使用它。 以下是我可以根据您的需求进行拼凑的内容:

 class CustomDataTableConverter : JsonConverter { public override bool CanConvert(Type objectType) { return (objectType == typeof(DataTable)); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { DataTable dt = (DataTable)value; JObject metaDataObj = new JObject(); foreach (DataColumn col in dt.Columns) { metaDataObj.Add(col.ColumnName, col.DataType.AssemblyQualifiedName); } JArray rowsArray = new JArray(); rowsArray.Add(metaDataObj); foreach (DataRow row in dt.Rows) { JObject rowDataObj = new JObject(); foreach (DataColumn col in dt.Columns) { rowDataObj.Add(col.ColumnName, JToken.FromObject(row[col])); } rowsArray.Add(rowDataObj); } rowsArray.WriteTo(writer); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JArray rowsArray = JArray.Load(reader); JObject metaDataObj = (JObject)rowsArray.First(); DataTable dt = new DataTable(); foreach (JProperty prop in metaDataObj.Properties()) { dt.Columns.Add(prop.Name, Type.GetType((string)prop.Value, throwOnError: true)); } foreach (JObject rowDataObj in rowsArray.Skip(1)) { DataRow row = dt.NewRow(); foreach (DataColumn col in dt.Columns) { row[col] = rowDataObj[col.ColumnName].ToObject(col.DataType); } dt.Rows.Add(row); } return dt; } } 

这是一个演示。 请注意,在序列化表时,列类型将作为JSON中数组的第一行写出。 在反序列化时,即使没有其他行,此元数据也用于使用正确的列类型和名称重新构建表。 (您可以通过注释掉行数据添加到表格顶部的两行来validation这一点。)

 class Program { static void Main(string[] args) { DataTable dt = new DataTable(); dt.Columns.Add("PackageID", typeof(int)); dt.Columns.Add("Amount", typeof(int)); dt.Columns.Add("Auto_sync", typeof(bool)); dt.Columns.Add("Color", typeof(string)); // Comment out these two lines to see the table with no data dt.Rows.Add(new object[] { 226, 15000, true, "BLUE" }); dt.Rows.Add(new object[] { 500, 15000, true, "PEACH" }); Foo foo = new Foo { BrokerID = "998", AccountID = "1313", Packages = dt }; JsonSerializerSettings settings = new JsonSerializerSettings(); settings.Converters.Add(new CustomDataTableConverter()); settings.Formatting = Formatting.Indented; string json = JsonConvert.SerializeObject(foo, settings); Console.WriteLine(json); Console.WriteLine(); Foo foo2 = JsonConvert.DeserializeObject(json, settings); Console.WriteLine("BrokerID: " + foo2.BrokerID); Console.WriteLine("AccountID: " + foo2.AccountID); Console.WriteLine("Packages table:"); Console.WriteLine(" " + string.Join(", ", foo2.Packages.Columns .Cast() .Select(c => c.ColumnName + " (" + c.DataType.Name + ")"))); foreach (DataRow row in foo2.Packages.Rows) { Console.WriteLine(" " + string.Join(", ", row.ItemArray .Select(v => v != null ? v.ToString() : "(null)"))); } } } class Foo { public string BrokerID { get; set; } public string AccountID { get; set; } public DataTable Packages { get; set; } } 

输出:

 { "BrokerID": "998", "AccountID": "1313", "Packages": [ { "PackageID": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "Amount": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "Auto_sync": "System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "Color": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" }, { "PackageID": 226, "Amount": 15000, "Auto_sync": true, "Color": "BLUE" }, { "PackageID": 500, "Amount": 15000, "Auto_sync": true, "Color": "PEACH" } ] } BrokerID: 998 AccountID: 1313 Packages table: PackageID (Int32), Amount (Int32), Auto_sync (Boolean), Color (String) 226, 15000, True, BLUE 500, 15000, True, PEACH 

小提琴: https : //dotnetfiddle.net/2TwpLf

您可以向json添加架构: http : //json-schema.org/example1.html

你的api方法签名是什么样的? 如果要传入要反序列化的json字符串到对象中,则您已经拥有对象本身的列信息。 我建议将你的api方法签名改为:

 [HttpPost, Route("packages")] public IHttpActionResult Packages(IEnumerable packages) 

然后,您可以将该列表用于数据表,或者只是枚举列表。