使用C#进行高级JSON序列化

时间:2014-09-23 19:55:02

标签: c# arrays json serialization

我想在本文中进一步扩展:http://philcurnow.wordpress.com/2013/12/29/serializing-and-deserializing-json-in-c/

那里的海报讨论了如何反序列化JSON并使用一组对象序列化它们,但是他们忽略了如何在请求中做一个对象数组。

我期待的是更先进一点。我有一组需要根据SQL存储过程发送到服务器的数据。基本上这个数据是一系列用户,他们的基本信息,但我正在使用的API在JSON请求中的数组中有这些对象,因为他们处理许多其他用户以及他们的API。

这里添加了澄清 - 这就是我需要基于SQL select存储过程的最终请求。该过程将从不同的表和数据库中提取几个数据,并为我编译这些项目。我希望最终结果采用以下格式:

{
    "api_key" : "123456XYZBLahBlahBlah",
    "account_id": "12345",
    "recipients": [
            {
                 "first_name": "Sam",
                    "last_name": "Goodfeet",
                 "address1": "123B",
                    "email": "user@test.com",
                    "cellphone": "123-123-1234",
                    "external_db_id": "t12312423"
            },
            {
                  "first_name": "Beth",
                  "last_name": "Goodfeet",
                 "address1": "123B",
                 "email": "user2@test.com",
                 "cellphone": "",
                    "external_db_id": "t45617777"
            }, 
{ recipient #3}, 
{recipient #4}….
        ]
}

我需要做的是把我的sql表移到上面的JSON结构中。我可以使用数据表或数据集执行此操作,还是应该根据数据集创建列表?我是否需要创建多个类文件来处理JSON对象的子数组?一个用于收件人,另一个用于更新流程请求,然后将它们序列化为:

[DataContract]
class Recipient
{
    [DataMember(Name = "external_db_id")]
    public string nameID { get; set; } //Name id - Required
    [DataMember(Name = "first_name")]
    public string firstname { get ; set; } //First Name Required
    [DataMember(Name = "last_name")]
    public string lastname { get; set; } //Last Name Required
    [DataMember(Name = "address1")]
    public string unitNumber { get; set; } //Unit number - Required
    [DataMember]
    public string email { get; set; } //Email address to notify -Can be blank
    [DataMember]
    public string cellphone { get; set; } //Cell to text - Can be blank
    [DataMember(Name = "pe_alert")]
    public int emailAlert { get; set; } //Email notification preference - Can be blank, if email is not null this defaults to 1
    [DataMember(Name = "pt_alert")]
    public int phoneAlert { get; set; } //Phone notification preference - Can be blank, if cellphone is not null this defaults to 1
}

[DataContract]
class updateRecipientList
{
    [DataMember]
    public string api_key { get; set; }
    [DataMember]
    public string account_id { get; set; }
    [DataMember]
    public Recipient recipient { get; set; }
}

还是有另一种方法可能更可行。请注意我不想使用JSON.org库。要将该库添加到我们的项目中是不可能的。我正在使用内置于框架中的内部JSON序列化和反序列化控件。我相当肯定这可以用这些库来完成。我也被迫使用框架3.5。

此外,我想知道为我发送发布数据的最佳方法是什么。每个请求也有超过1000个条目要发送。我应该注意JSON请求大小是否有任何限制?提前致谢。我希望我已经很好地解释了这一点。

1 个答案:

答案 0 :(得分:0)

为了完整起见,我在这里得到了一些帮助,因为这里没有太多帮助。我会发布我最终的内容。我已经对数据敏感,因此您可能需要对其进行修改以适合您自己的使用。

[DataContract]
class Request
{
    [DataMember]
    public string api_key { get; set; }
    [DataMember]
    public string account_id { get; set; }
    [DataMember]
    public List<Recipient> recipients { get; set; } //THIS is what I missed originally
}

[DataContract]
class Recipient 
{
    [DataMember(Name = "name_id")]
    public string nameID { get; set; } 
    [DataMember(Name = "first_name")]
    public string firstname { get ; set; } 
    [DataMember(Name = "last_name")]
    public string lastname { get; set; } 
    [DataMember(Name = "Unit_number")]
    public string unitNumber { get; set; } 
    [DataMember]
    public string email { get; set; } 
    [DataMember]
    public string cellphone { get; set; }
}

Request request = new Request();

//setup request object
request.account_id = accountID;
request.api_key = apiKey; 
request.recipient = new List<Recipient>(); //Don't forget to do this or you'll have null reference when you add the recipient objects to the request list

//setup connection to stored proc
SqlConnection sqlCon = new SqlConnection("ConnectionStringHere");

//Read data from stored proc
using (SqlCommand sqlCmd = new SqlCommand("StoredProcedureNameHere", sqlCon))
{
    //setup command type
    sqlCmd.CommandType = CommandType.StoredProcedure;

    //Open connection
    sqlCon.Open();

    //Execute the reader
    using (SqlDataReader sqlRd = sqlCmd.ExecuteReader())
    {
        //while we still have data keep going
        while (sqlRd.Read())
        {
            Recipient recipient = new Recipient();
            recipient.nameID = sqlRd["column1"].ToString();
            recipient.unitNumber = sqlRd["column2"].ToString().Trim(); //example of trimming out white space
            recipient.firstname = sqlRd["column3"].ToString();
            recipient.lastname = sqlRd["column4"].ToString();
            recipient.email = sqlRd["column5"].ToString();
            recipient.cellphone = Regex.Replace(sqlRd["column6"].ToString(), "[^.0-9]", ""); //example of setting the value to only numbers removing anything else

            //store recipient to request object
            request.recipients.Add(recipient); //This will put the items in the object for proper serialization based on the object structure
        }
    } 

    //finished close connection
    sqlCon.Close();
}

//serialize dataset into JSON request
string jsonString = SerializeJSon<Request>(request); //Link to function for this code can be found in the original question

一旦这样做,您就可以轻松地将信息发布到您想要的任何服务上。在原始文章中有一些关于如何做到这一点的代码以及我在问题中链接的内容。

我基本上决定使用请求对象中的收件人对象列表,而不是将数据设置为数据集,然后再设置为对象。相反,我使用datareader遍历数据集,以便在通过数据时将每个收件人添加到请求对象。我在初始测试中有大约500个用户,并且在完全集成完成后最终我们可能有超过160,000个收件人。如果我遇到问题,我会在这里发表评论。我仍然不确定JSON请求大小限制。我没有集成任何类型的压缩,如上面提到的ilansch,但它可能需要大型数据集。

基本上,当您使用我在原始问题上链接的帖子的序列化过程代码序列化请求对象时,它基本上会解码您在请求对象中有一个收件人子阵列并在其中创建JSON收件人数组的事实完全按照我概述的请求格式化我希望它看起来。原始文章代码对于该过程是可靠的,因此我建议使用该代码。它为我节省了大量时间和头痛。

我认为唯一的缺点就是它在循环数据集时绑定了SQL服务器。我原本想将数据设置为数据集,然后将该对象数据移动到请求对象,但这更简单,感觉更精简。我不知道是否有一种更有效的方法可以减轻SQL服务器本身的负担,并增加代码库的负载(我个人更喜欢这样)。因此,如果您使用的是非常大的数据集,那么在使用此代码时,您可能希望将其保留在脑后。在我的情况下,我认为如果我使用该方法,它将只允许连接更快地关闭一小部分。显然,随着读入内存的数据量的增加,它可能会呈指数级增长。根据数据大小,您可以考虑修改此操作,而不是打开连接并在读取数据时创建对象信息。

无论如何,我希望将来可以帮助某人。