如何在WCF中以最佳方式将.NET DataTable序列化为JSON?

15

当我配置WCF使用jSON序列化,并在我的数据契约中包含一个DataTable时,它会先将DataTable序列化为XML,然后再将整个DataContract序列化为jSON。 我希望DataTable被序列化为jSON而不是XML。

我的问题是:

  1. 为什么它要先将DataTable序列化为XML?
  2. 我该如何让它序列化为jSON?

欢迎来到S.O.您尝试过哪些方法将数据序列化为JSON格式? - Daniele Armanasco
请考虑将您的数据表转换为JSON格式。参考以下链接:https://dev59.com/RWQm5IYBdhLWcg3wtA0_ - Ali Umair
4个回答

14
  1. DataTable是一个纯.NET结构,无法通过JSON以不丢失数据的方式轻松表示。DataTable包含大量的额外信息,这些信息JSON无法存储:主键、自增、允许为空、标题、数据类型、索引等。将DataTable序列化为XML/Binary是.NET本地化序列化的唯二方式。然后将这个XML序列化的DataTable转换成JSON。

  2. 使用JSON.NETFastJSON将DataTable转换为一个纯净的、可与JSON兼容的版本,这个版本可以被任何JSON客户端使用,而不仅仅是.NET WCF客户端。你将会失去在(1)中提到的所有DataTable自定义属性,只得到字段名/值JSON对。采用这种方式存储是低效的,因为每行都需要重复字段名。

不要在DataContract中使用DataTable。如果您想要获得DataTable带来的好处,而您的客户端始终会是.NET客户端,那么通过二进制序列化将DataTable序列化为字节数组,然后可选地压缩生成的序列化字节流。在DataContract中公开一个字节数组。这将在客户端(解压缩和二进制反序列化之后)提供一个高效、完全不丢失的DataTable版本,而不是水下版本的DataTable JSON(如(2)所提供)。


非常好的答案。谢谢你。我的客户并不都是.NET,我很快发现了你提到的低效率。我将尝试修改这种方法,以便不必在每行中包含列/字段名称。 - rhyno
我知道这是一个旧的线程,但fastjson从2011年6月之前发布的1.7.7版本开始支持datatable序列化/反序列化。而且xml格式效率低下,它为每个字段和行都包含繁琐的标记。 - user757095
@Keith Blows,如何序列化DataTable的List?您有什么建议吗? - Xegara
我创建了这个gist来测试Newtonsoft.Json(在linqpad中运行)。序列化的结果符合你的期望。 - Jared Beach

6

试试这个:

public string ConvertDataTabletoString(System.Data.DataTable dt)
{
    System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
    List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
    Dictionary<string, object> row;
    foreach (System.Data.DataRow dr in dt.Rows)
    {
        row = new Dictionary<string, object>();
        foreach (System.Data.DataColumn col in dt.Columns)
        {
            row.Add(col.ColumnName, dr[col]);
        }
        rows.Add(row);
    }
    return serializer.Serialize(rows);
}

4

我遇到了同样的问题,我的wcf服务在将数据集转换为Json时未能正确格式化Json。我通过以下解决方案使其正常工作:

using System.ServiceModel.Channels;
using System.ServiceModel.Web;

dsData是我的数据集。

string json = Newtonsoft.Json.JsonConvert.SerializeObject(dsData);
return WebOperationContext.Current.CreateTextResponse(json, "application/json;charset=utf-8", System.Text.Encoding.UTF8);

"Message"将是返回类型。


这个答案今天真的救了我的命 :) 我放弃了寻找从数据库返回DataTable到JSON的简单方法,而不需要为每个表/过程显式声明对象。 我的错误在于我的OperationContract只是简单地返回序列化的json字符串。这样,例如,需要在客户端使用JSON.parse。将返回类型更改为System.ServiceModel.Channels.Message并像上面所示使用WebOperationContext.Current.CreateTextResponse(string) 完美地运行! :) - Skipper
我从未想过使用WCF WS可以做这样的事情 - 设置响应而不仅仅是返回int/string/class/List<T>等。 - Skipper

2
根据其主页上的图表,Json.NET 真的是您唯一的选择 - 您可以从 NuGet 快速获取它。幸运的是,这是一个非常好的库,非常易于使用。
string json = JsonConvert.SerializeObject(myDataSet, new DataSetConverter());

请注意,Rich Strahl 在一篇非常详细的文章中提供了更多的细节,并且他还包括了一些自定义工作,以使用(相当广泛的)自定义转换器来使用JavaScriptSerializer进行比较。

1
这个方法起初有效,但我很快发现每行数据都包含数据列/字段名称,正如Keith所指出的那样,这使其效率非常低下。因此,我将尝试修改 DataTableConverter 和 DataRowConverter ,以便不重复使用所有这些列/字段名称。 - rhyno
@rhyno,你最终是如何解决不重复所有列/字段名称的问题的?我有一个想法,但如果你已经完成了这个任务,那会节省我很多时间。 - DeadlyChambers

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接