c# - 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_*
属性的列表/数组的根对象。
感谢您为解决此问题提供的任何帮助。
解决方案
你的 JSON 基本上代表了一个string
-BasicList
对的字典,与关于整体结果的一些其他属性混合在一起。这种格式使其更难以使用。(如果字典数据在 JSON 的子对象中会更好。)
处理这种情况的最简单方法是利用 Json.Net 的“扩展数据”功能。
这是您需要做的:
Dictionary<string, JToken>
在您的BasicListResponse
类中创建一个私有属性并使用该[JsonExtensionData]
属性对其进行标记。这将在反序列化期间捕获字典数据。list
将您的属性 更改为 aList<BasicList>
而不是 aDictionary<string, BasicList>
。(我也会用适当的大写对其进行重命名,以与您的其他属性保持一致。)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
推荐阅读
- vue.js - VueJS - 使用过滤器或基础组件来格式化数字
- html - Flex 面包屑:如何设置相等的高度并换行
- sql - Sql通配符不是结束字符串
- java - 查找奇偶校验异常值 CodeWars
- python - 用python抓取网页的所有颜色
- node.js - 使用“--experimental-modules”编译时如何修复“ReferenceError:require is not defined”错误?
- angular - 在 IE11 中更新 ngModel 后触发 ngbRadioGroup 点击事件
- excel - 将一列中所有单元格中的值添加到另一列中的相应单元格中,然后清除原始单元格
- dart - 导航器多次推送同一个屏幕
- javascript - 触发数组中的特定元素,然后遍历其他数组