首页 > 解决方案 > JsonConvert.DeserializeObject 未按预期从 JSON 转换响应对象

问题描述

我正在为 C#.NET 创建一个 ActiveCampaign V1.1 包装器,并创建一个使用 ( https://www.activecampaign.com/api/example.php?call=list_list )列出 ContactLists 的类

之后返回的响应对象JsonConvert.DeserializeObject<BasicListResponse>(JSON)确实填充了非列表属性,但 JSON 的列表部分未转换。

我尝试了以下BasicListResponse实现:

public class Result
{
    [JsonProperty("result_code")]
    public int ResultCode { get; set; }

    [JsonProperty("result_message")]
    public string ResultMessage { get; set; }

    [JsonProperty("result_output")]
    public string ResultOutput { get; set; }
}

public class BasicListResponse : Result
{      
    public Dictionary<string, BasicList> list { get; set; }
}

public class BasicList
{
    [JsonProperty("id")]
    public string Id { get; set; }

    [Required]
    [JsonProperty("name")]
    public string Name { get; set; }

    [JsonProperty("cdate")]
    public DateTime CreatedOn { get; set; }

    [JsonProperty("private")]
    public bool Private { get; set; }

    [JsonProperty("userid")]
    public string UserId { get; set; }

    [JsonProperty("subscriber_count")]
    public int SubscriberCount { get; set; }
}

我也尝试过使用json2csharp或 VS > Paste Special 但输出有编号的类而不是对象列表。

JSON响应如下:

{
    "0": {
        "id": "1",
        "name": "xxxxx xxxxxx xxxxxxx",
        "cdate": "2019-10-27 22:43:23",
        "private": "0",
        "userid": "1",
        "subscriber_count": 1
    },
    "1": {
        "id": "2",
        "name": "yyyyy yyyyy yyyyy",
        "cdate": "2019-10-27 22:44:03",
        "private": "0",
        "userid": "1",
        "subscriber_count": 0
    },
    "result_code": 1,
    "result_message": "Success: Something is returned",
    "result_output": "json"
}

我在包装器中提取了Dictionary<T,T>,但列表始终为 NULL。

如果我重新序列化BasicListResponse结果如下

{ "list": null, "result_code": 1, "result_message": "Success: Something is returned", "result_output": "json" }

我希望将BasicListResponse其用作包含具有三个字符串result_*属性的列表/数组的根对象。

感谢您为解决此问题提供的任何帮助。

标签: c#.netjsonjson.netdeserialization

解决方案


你的 JSON 基本上代表了一个string-BasicList对的字典,与关于整体结果的一些其他属性混合在一起。这种格式使其更难以使用。(如果字典数据在 JSON 的子对象中会更好。)

处理这种情况的最简单方法是利用 Json.Net 的“扩展数据”功能。

这是您需要做的:

  1. Dictionary<string, JToken>在您的BasicListResponse类中创建一个私有属性并使用该[JsonExtensionData]属性对其进行标记。这将在反序列化期间捕获字典数据。
  2. list将您的属性 更改为 aList<BasicList>而不是 a Dictionary<string, BasicList>。(我也会用适当的大写对其进行重命名,以与您的其他属性保持一致。)
  3. OnDeserialized添加如下所示的私有方法,List<BasicList>以在反序列化过程结束时从扩展字典中填充。

所以你的BasicListResponse班级应该是这样的:

public class BasicListResponse : Result
{
    public List<BasicList> List { get; set; }

    [JsonExtensionData]
    private Dictionary<string, JToken> Data { get; set; }

    [OnDeserialized]
    private void OnDeserialized(StreamingContext context)
    {
        List = Data?.OrderBy(kvp => kvp.Key)
                    .Select(kvp => kvp.Value.ToObject<BasicList>())
                    .ToList();
    }
}

我们还需要解决另一个小问题:在您的BasicList类中,您将Private属性定义为bool,但在 JSON 中,它是一个包含数字的字符串。由于类型不兼容,这将导致反序列化失败。要使其工作,您可以更改Private为字符串,然后在代码中的其他位置处理值的解释,或者您可以执行以下操作:

public class BasicList
{
    ...

    [JsonProperty("private")]
    private string PrivateAsString { get; set; }

    [JsonIgnore]
    public bool Private
    {
        get { return PrivateAsString != "0"; }
        set { PrivateAsString = value ? "1" : "0"; }
    }

    ...
}

通过这些更改,您可以反序列化到您的BasicListResponse类,并且一切都应该正常工作。

var result = JsonConvert.DeserializeObject<BasicListResponse>(json);

在这里工作演示:https ://dotnetfiddle.net/9MmSuG


推荐阅读