C# 将数据行转换为JSON对象

C# 将数据行转换为JSON对象,c#,.net,json,datatable,json.net,C#,.net,Json,Datatable,Json.net,我有一个DataTable,它只有一行,看起来像 America | Africa | Japan | ------------------------------------------------------------- {"Id":1,"Title":"Ka"} | {"Id":2,"Title":"Sf"} | {"Id":3,"Title":"Ja","Values":{"ValID":4,

我有一个
DataTable
,它只有一行,看起来像

   America              |  Africa               |     Japan     |   
   -------------------------------------------------------------
  {"Id":1,"Title":"Ka"} | {"Id":2,"Title":"Sf"} | {"Id":3,"Title":"Ja","Values":{"ValID":4,"Type":"Okinawa"}} 
DataTable
列为美国、非洲、日本

现在我想将
DataTable
转换为JSON,使JSON看起来像

{
"America": {
    "Id": 1,
    "Title": "Ka"
},
"Africa": {
    "Id": 2,
    "Title": "Sf"
},
"Japan": {
    "Id": 3,
    "Title": "Ja",
    "Values": {
        "ValID": 4,
        "Type": "Okinawa"
    }
  }
}  
我的尝试是:

string js = JSonConvverter.Serializeobject(datatable);
var objType =  JObject.Parse(js);

但它不起作用。如有任何帮助,将不胜感激。

拼写?对“SerializeObject”方法的调用不应该是:

string js = JsonConvert.SerializeObject(datatable);

还可以看到一个关于转换的类似问题。

就像Gazzi说的那样,您应该包括Visual Studio中包含的NewtonSoft.Json库

要得到一个类似于您所描述的对象,您应该创建一个类似Country.cs的数据模型,该模型如下所示

[Serializable]
public class CountryModel {
   public int ID { get; set; }
   public string Title { get; set; }
   public List<ValueModel> Values { get; set; }
}

[Serializable]
public class ValueModel {
   public int ValueID { get; set; }
   public string Type { get; set; }
}
[可序列化]
公共类模型{
公共int ID{get;set;}
公共字符串标题{get;set;}
公共列表值{get;set;}
}
[可序列化]
公共阶级价值模型{
public int ValueID{get;set;}
公共字符串类型{get;set;}
}
创建一个助手函数,将表数据转换为这些模型。然后,您可以根据需要使用Newtonsoft库对数据进行序列化/反序列化。

假设您使用的是一个特殊的内置转换器,它以行数组的形式输出数据表,其中每一行都序列化为列名/值对,如您的问题所示。虽然也有,但没有特定的内置转换器。因此,当直接序列化
DataRow
Json.NET时,将序列化
DataRow
的所有字段和属性,从而产生更详细的输出-这是您不希望的

DataTable
使用的更紧凑的形式序列化
DataRow
最简单的方法是使用
JArray
将整个表序列化为一个
数组,然后选择与要序列化的
DataRow
索引相同的数组项:

var rowIndex = 0;

var jArray = JArray.FromObject(datatable, JsonSerializer.CreateDefault(new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }));

var rowJToken = jArray[rowIndex];
var rowJson = rowJToken.ToString(Formatting.Indented);  // Or Formatting.None if you prefer
因为您的表只有一行,
rowIndex
应该是
0
。更一般地说,如果您不知道给定
数据行的索引,请参阅

演示小提琴#1

或者,如果您的表足够大,序列化整个表会影响性能,则可以引入for
DataRow
,将该行作为对象写入JSON:

public class DataRowConverter : JsonConverter<DataRow>
{
    public override DataRow ReadJson(JsonReader reader, Type objectType, DataRow existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException(string.Format("{0} is only implemented for writing.", this));
    }

    public override void WriteJson(JsonWriter writer, DataRow row, JsonSerializer serializer)
    {
        var table = row.Table;
        if (table == null)
            throw new JsonSerializationException("no table");
        var contractResolver = serializer.ContractResolver as DefaultContractResolver;

        writer.WriteStartObject();
        foreach (DataColumn col in row.Table.Columns)
        {
            var value = row[col];

            if (serializer.NullValueHandling == NullValueHandling.Ignore && (value == null || value == DBNull.Value))
                continue;

            writer.WritePropertyName(contractResolver != null ? contractResolver.GetResolvedPropertyName(col.ColumnName) : col.ColumnName);
            serializer.Serialize(writer, value);
        }
        writer.WriteEndObject();
    }
}
注:

  • 虽然序列化单个
    数据行
    是有意义的,但反序列化一个数据行却没有意义,因为
    数据行
    不是一个独立的对象;它只存在于某些父数据表中。因此,
    ReadJson()
    没有实现

  • Json.NET中引入了was。在早期版本中,继承自


Demo fiddle#2.

作为找到答案的替代方法,您可以使用
ExpandoObject
快速而轻松地将单行呈现为JSON,如下所示:

var expando=new System.Dynamic.ExpandoObject()作为IDictionary;
foreach(myRow.Table.Columns中的数据列col)
{
eo[col.ColumnName]=myRow[col];
}
var json=JsonConvert.SerializeObject(expando);
检查Json.NET
var row = datatable.Rows[rowIndex];

var settings = new JsonSerializerSettings
{
    NullValueHandling = NullValueHandling.Ignore,
    Converters = { new DataRowConverter() },
};
var rowJson = JsonConvert.SerializeObject(row, Formatting.Indented, settings);