【问题标题】:Deserialize Active campaign's beautiful json output to c# object将 Active 活动的漂亮 json 输出反序列化为 c# 对象
【发布时间】:2019-01-22 10:17:56
【问题描述】:

...“美丽”在这里是讽刺的。

当您调用 Active Campaign 的 list_view 端点,并希望在 json 响应中得到它,那么这就是您得到的 json 响应:

{
    "0": {
        "id": "4",
        "name": "Nieuwsletter 1",
        "cdate": "2018-11-22 03:44:19",
        "private": "0",
        "userid": "6",
        "subscriber_count": 2901
    },
    "1": {
        "id": "5",
        "name": "Newsletter 2",
        "cdate": "2018-11-22 05:02:41",
        "private": "0",
        "userid": "6",
        "subscriber_count": 2229
    },
    "2": {
        "id": "6",
        "name": "Newsletter 3",
        "cdate": "2018-11-22 05:02:48",
        "private": "0",
        "userid": "6",
        "subscriber_count": 638
    },
    "result_code": 1,
    "result_message": "Success: Something is returned",
    "result_output": "json"
}

现在我怎么能将它反序列化为一个对象?执行正常的 Edit => Paste Special => Paste JSON As Classes 给了我一个输出,我最终得到了名为 _2 的类。

另外,JsonConvert 抛出以下错误:Accessed JObject values with invalid key value: 2. Object property name expected. 所以它也不能真正反序列化它。我尝试使用dynamic 作为对象类型来转换。

我现在唯一能想到的是将第一个{ 替换为[,将最后一个} 替换为],然后删除所有"1" : 项,然后删除最后3 个属性。之后,我有一个易于转换的基本数组。但我有点希望有人有更好的解决方案,而不是深入研究 string.indexOf 和 string.Replace 派对......

【问题讨论】:

  • 所以像1,2,3这样的键只有三个,或者像0,1,2........N这样的键有无限的可能

标签: c# json json.net deserialization


【解决方案1】:

如果您的键/值对不是固定的并且数据必须是可配置的,那么 Newtonsoft.json 有一个可以在这里使用的功能,那就是[JsonExtensionData]Read more

现在在序列化对象时写入扩展数据。读取和写入扩展数据可以自动往返所有 JSON,而无需将每个属性添加到您要反序列化的 .NET 类型。只声明您感兴趣的属性,让扩展数据完成其余的工作。

在您的情况下,0,1,2,3.......N 的键/值对具有动态数据,因此您的课程将是

因此,创建一个属性来收集您的所有动态键/值对,其属性为[JsonExtensionData]。下面我创建了一个名称为DynamicData

class MainObj
{
    [JsonExtensionData]
    public Dictionary<string, JToken> DynamicData { get; set; }

    public int result_code { get; set; }
    public string result_message { get; set; }
    public string result_output { get; set; }
}

然后你可以像这样反序列化你的 JSON

string json = "Your json here"

MainObj mainObj = JsonConvert.DeserializeObject<MainObj>(json); 

编辑:

如果您想将动态键的值收集到类中,则可以在类结构下方使用。

class MainObj
{
    [JsonExtensionData]
    public Dictionary<string, JToken> DynamicData { get; set; }

    [JsonIgnore]
    public Dictionary<string, ChildObj> ParsedData
    {
        get
        {
            return DynamicData.ToDictionary(x => x.Key, y => y.Value.ToObject<ChildObj>());
        }
    }

    public int result_code { get; set; }
    public string result_message { get; set; }
    public string result_output { get; set; }
}

public class ChildObj
{
    public string id { get; set; }
    public string name { get; set; }
    public string cdate { get; set; }
    public string _private { get; set; }
    public string userid { get; set; }
    public int subscriber_count { get; set; }
}

然后你可以像这样反序列化你的 JSON

MainObj mainObj = JsonConvert.DeserializeObject<MainObj>(json);

然后您可以访问每个反序列化的数据,例如

int result_code = mainObj.result_code;
string result_message = mainObj.result_message;
string result_output = mainObj.result_output;

foreach (var item in mainObj.ParsedData)
{
    string key = item.Key;
    ChildObj childObj = item.Value;

    string id = childObj.id;
    string name = childObj.name;
    string cdate = childObj.cdate;
    string _private = childObj._private;
    string userid = childObj.userid;
    int subscriber_count = childObj.subscriber_count;
}

【讨论】:

  • 乍一看持怀疑态度,但后来证明这比其他解决方案更好(对不起,安迪),因为当使用默认方法来处理整个 json 请求和返回一个对象。这是两个答案的组合,因为我仍然需要像安迪的答案中所示那样循环遍历 DynamicData。
  • @AnuViswan,是的,这就是我编辑答案的原因,对于_private,您可以选择如何将其命名为:)
  • @CularBytes,谢谢,并回答更新以更适合您。查看答案中的编辑部分:)
  • 我收回了这一点,出于某种原因,我觉得 json 有点不同......顺便说一句,DynamicData 可以是私有的
  • @AnuViswan,是的,它可以是私有的,它是 OP 的选择,他/她想要它是公共的还是私有的。
【解决方案2】:

我会推荐来自Newtonsoft.Json 库的JObject

例如使用 C# 交互

// Assuming you've installed v10.0.1 of Newtonsoft.Json using a recent version of nuget
#r "c:\Users\MyAccount\.nuget\.nuget\packages\Newtonsoft.Json\10.0.1\lib\net45\Newtonsoft.Json.dll"

using Newtonsoft.Json.Linq;
var jobj = JObject.Parse(File.ReadAllText(@"c:\code\sample.json"));
foreach (var item in jobj)
{
     if (int.TryParse(item.Key, out int value))
     {
         Console.WriteLine((string)item.Value["id"]);

         // You could then convert the object to a strongly typed version
         var listItem = item.Value.ToObject<YourObject>();
      }
}

哪些输出:

 4
 5
 6

查看此页面了解更多详情

https://www.newtonsoft.com/json/help/html/QueryingLINQtoJSON.htm

【讨论】:

    猜你喜欢
    • 2011-03-09
    • 2015-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-30
    相关资源
    最近更新 更多