如何反序列化包含对象或对象数组的JSON对象

时间:2018-03-05 17:01:09

标签: c# json whois

我试图反序列化我从ARIN whois REST API返回的JSON响应。我是JSON的新手,但我认为他们会根据结果返回两种不同的模式,而且我很难将其分开。

如果有多个 net 对象,则返回JSON的删节版本:

{
  "nets": {
    "@xmlns":{"ns3":"http:\/\/www.arin.net\/whoisrws\/netref\/v2",
    "net": [{
        "customerRef": {
          "@name": "Internet Customer",
        },
      }, {
        "orgRef": {
          "@name": "Internet Service Provider",
        },
      }
    ]
  }
}

请注意,网络 net 对象的数组。当只返回一个 net 对象时,JSON如下所示:

{
  "nets": {
    "@xmlns":{"ns3":"http:\/\/www.arin.net\/whoisrws\/netref\/v2",
    "net": {
        "orgRef": {
          "@name": "Internet Customer",
        },
      }
  }
}

在这种情况下, nets 是一个包含单个 net 对象的对象。我可以使用数组或单个嵌入对象定义我的类,但使用JsonConvert.DeserializeObject<ARINWhois>(response)进行反序列化会对不同意我的架构的结果抛出异常。

我考虑过两个选择:

  1. 使用JsonTextReader手动反序列化所有内容。
  2. 定义两个对象模式,如果抛出异常则重试另一个。
  3. 是否有更简单,更优雅的解决方案?

1 个答案:

答案 0 :(得分:0)

感谢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; }
}