如何反序列化包含对象或对象数组的 JSON 对象
How to deserialize a JSON object containing an object or object array
我正在尝试反序列化从 ARIN whois REST API 返回的 JSON 响应。我是 JSON 的新手,但我 认为 他们根据结果返回两种不同的模式,我很难把它拆开。
这是 JSON 的简化版本,如果有多个 net 对象则返回:
{
"nets": {
"@xmlns":{"ns3":"http:\/\/www.arin.net\/whoisrws\/netref\/v2",
"net": [{
"customerRef": {
"@name": "Internet Customer",
},
}, {
"orgRef": {
"@name": "Internet Service Provider",
},
}
]
}
}
注意 nets 是 net 对象的数组。当只有一个 net 对象返回时,JSON 看起来像这样:
{
"nets": {
"@xmlns":{"ns3":"http:\/\/www.arin.net\/whoisrws\/netref\/v2",
"net": {
"orgRef": {
"@name": "Internet Customer",
},
}
}
}
在这种情况下,nets 是一个包含单个 net 对象的对象。我可以用数组或单个嵌入式对象定义我的 class,但使用 JsonConvert.DeserializeObject<ARINWhois>(response)
反序列化会在不符合我的架构的结果上引发异常。
我考虑过两种选择:
- 用
JsonTextReader
手动反序列化。
- 定义两个对象模式并在抛出异常时用另一个重试。
有没有更简单优雅的解决方案?
感谢 Eser22,他向我指出了 JsonConverter 的使用,它完全符合我的需要。 How to Handle both a single item and an array for the same property 是一个很好的解释。完美运行!
这是我的代码的最终版本。
/*
* parse the response
*/
ARINWhois WhoisResp = JsonConvert.DeserializeObject<ARINWhois>(response);
/*
* custom converter
*/
class SingleOrArrayConverter<T> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(List<T>));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
if (token.Type == JTokenType.Array)
{
return token.ToObject<List<T>>();
}
return new List<T> { token.ToObject<T>() };
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
/*
* data models
*/
public class ARINWhois
{
[JsonProperty("nets")]
public ARINNets Network { get; set; }
}
public class ARINNets
{
[JsonProperty("net")]
[JsonConverter(typeof(SingleOrArrayConverter<ARINNet>))]
public List<ARINNet> Networks;
}
public class ARINNet
{
[JsonProperty("registrationDate")]
public ARINregistrationDate RegistrationDate;
[JsonProperty("orgRef")]
public ARINorgRef Organization;
[JsonProperty("customerRef")]
public ARINcustomerRef Customer;
}
public class ARINregistrationDate
{
[JsonProperty("$")]
public string date { get; set; }
}
public class ARINorgRef
{
[JsonProperty("@name")]
public string name { get; set; }
[JsonProperty("@handle")]
public string handle { get; set; }
}
public class ARINcustomerRef
{
[JsonProperty("@name")]
public string name { get; set; }
[JsonProperty("@handle")]
public string handle { get; set; }
}
我正在尝试反序列化从 ARIN whois REST API 返回的 JSON 响应。我是 JSON 的新手,但我 认为 他们根据结果返回两种不同的模式,我很难把它拆开。
这是 JSON 的简化版本,如果有多个 net 对象则返回:
{
"nets": {
"@xmlns":{"ns3":"http:\/\/www.arin.net\/whoisrws\/netref\/v2",
"net": [{
"customerRef": {
"@name": "Internet Customer",
},
}, {
"orgRef": {
"@name": "Internet Service Provider",
},
}
]
}
}
注意 nets 是 net 对象的数组。当只有一个 net 对象返回时,JSON 看起来像这样:
{
"nets": {
"@xmlns":{"ns3":"http:\/\/www.arin.net\/whoisrws\/netref\/v2",
"net": {
"orgRef": {
"@name": "Internet Customer",
},
}
}
}
在这种情况下,nets 是一个包含单个 net 对象的对象。我可以用数组或单个嵌入式对象定义我的 class,但使用 JsonConvert.DeserializeObject<ARINWhois>(response)
反序列化会在不符合我的架构的结果上引发异常。
我考虑过两种选择:
- 用
JsonTextReader
手动反序列化。 - 定义两个对象模式并在抛出异常时用另一个重试。
有没有更简单优雅的解决方案?
感谢 Eser22,他向我指出了 JsonConverter 的使用,它完全符合我的需要。 How to Handle both a single item and an array for the same property 是一个很好的解释。完美运行!
这是我的代码的最终版本。
/*
* parse the response
*/
ARINWhois WhoisResp = JsonConvert.DeserializeObject<ARINWhois>(response);
/*
* custom converter
*/
class SingleOrArrayConverter<T> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(List<T>));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
if (token.Type == JTokenType.Array)
{
return token.ToObject<List<T>>();
}
return new List<T> { token.ToObject<T>() };
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
/*
* data models
*/
public class ARINWhois
{
[JsonProperty("nets")]
public ARINNets Network { get; set; }
}
public class ARINNets
{
[JsonProperty("net")]
[JsonConverter(typeof(SingleOrArrayConverter<ARINNet>))]
public List<ARINNet> Networks;
}
public class ARINNet
{
[JsonProperty("registrationDate")]
public ARINregistrationDate RegistrationDate;
[JsonProperty("orgRef")]
public ARINorgRef Organization;
[JsonProperty("customerRef")]
public ARINcustomerRef Customer;
}
public class ARINregistrationDate
{
[JsonProperty("$")]
public string date { get; set; }
}
public class ARINorgRef
{
[JsonProperty("@name")]
public string name { get; set; }
[JsonProperty("@handle")]
public string handle { get; set; }
}
public class ARINcustomerRef
{
[JsonProperty("@name")]
public string name { get; set; }
[JsonProperty("@handle")]
public string handle { get; set; }
}