0

I'm trying to deserialize the JSON response that I get back from the ARIN whois REST API. I'm new to JSON but I think they are returning two different schemas depending on the results and I'm having a hard time taking it apart.

Here is an abridged version of the JSON that's returned if there are multiple net objects:

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

Note that nets is an array of net objects. When there is only one net object returned, the JSON looks like this:

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

In this case nets is an object that contains a single net object. I can define my class with an array or with a single embedded object but deserializing with JsonConvert.DeserializeObject<ARINWhois>(response) will throw an exception on results that don't agree with my schema.

I've considered two options:

  1. Deserialize it all by hand with JsonTextReader.
  2. Define both object schemas and retry with the other one if an exception is thrown.

Is there is an easier and more elegant solution?

GMAP
  • 19
  • 9
  • 2
    Note that neither of your extracts are valid JSON on their own (the commas after the last elements are not allowed). – Jeroen Mostert Mar 05 '18 at 17:04
  • My bad. The original JSON is quite long and my cut/paste foo was weak. – GMAP Mar 05 '18 at 17:07
  • Would be helpful if you post your model also, such as `ARINWhois` etc. – penleychan Mar 05 '18 at 17:16
  • 1
    Possible duplicate of [How to handle json that returns both a string and a string array?](https://stackoverflow.com/questions/22052430/how-to-handle-json-that-returns-both-a-string-and-a-string-array) – Eser Mar 05 '18 at 17:23
  • Thanks for the link! I think that might be my solution but I need to go off and study it a bit. If that doesn't resolve it, I will post my model for `ARINWhois` and we can pick up where we left off. – GMAP Mar 05 '18 at 18:16
  • That link wasn't exactly what I needed but it led to [link]https://stackoverflow.com/questions/18994685/how-to-handle-both-a-single-item-and-an-array-for-the-same-property-using-json-n which was. Thanks! – GMAP Mar 06 '18 at 15:53

1 Answers1

0

Thanks to Eser22 who pointed me toward the use of JsonConverter which does exactly what I need. How to Handle both a single item and an array for the same property is an excellent explanation. Works perfectly!

Here is the final version of my code.

/*
 * 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; }
}
GMAP
  • 19
  • 9