1

I'm trying to connect with an external API. It gives me the results in JSON and depending my search term, it could give zero, one or more-than-one results.

I have mapped this to a C# class as follows:

Class Item
- List<ItemResult> Results { get; set; }
- Other properties, such as Name or Description (strings)

Whenever the JSON has an array of ItemResult (marked with []), it works fine, when the JSON has a single ItemResult (marked with {}), the parsing gives an error, because it expects a collection or array.

My request is done as follows:

private T DoRequest<T>(string url)
{
    try
    {
        var webRequest = (HttpWebRequest) WebRequest.Create(url);
        webRequest.Method = "GET";
        webRequest.Accept = "application/json";
        webRequest.UserAgent = UserAgent;

        var webResponse = webRequest.GetResponse();
        using (var streamReader = new StreamReader(webResponse.GetResponseStream()))
        {
            var responseResult = streamReader.ReadToEnd();
            return JsonConvert.DeserializeObject<T>(CorrectJson(responseResult));
        }
    }
    catch (Exception e)
    {
        UtilityBL.LogError(e.Message);
        return default(T);
    }
}

My question is: how can I make sure that this code handles both JSON results with an array of ItemResults as well as a single ItemResult? Perhaps I need to manually adjust the JSON result?

Thanks!

Edit:

it's similar to this question, but instead of JQuery or Javascript, I need a .NET solution: How to read both single object & array of objects in json using javascript/jquery

I have also tried following code, but it fails since JsonConvert tells me there now are 2 Album matches:

public class Albummatches
{
    [JsonProperty("Album")]
    public List<Album> Albums { get; set; }

    [JsonProperty("Album")]
    public Album Album {
        set
        {
            Albums = new List<Album>();
            Albums.Add(value);
        }
    }
}
Community
  • 1
  • 1
Recipe
  • 1,398
  • 3
  • 16
  • 29
  • Duplilcate question: http://stackoverflow.com/questions/25580680/deserialize-from-json-where-can-be-single-t-object-or-array-of-t-into-listt/25582239#25582239 – brz Aug 31 '14 at 13:51
  • funny, since that's a duplicate of [http://stackoverflow.com/questions/18994685/how-to-handle-both-a-single-item-and-an-array-for-the-same-property-using-json-n](http://stackoverflow.com/questions/18994685/how-to-handle-both-a-single-item-and-an-array-for-the-same-property-using-json-n) :) – Noctis Aug 31 '14 at 13:57

2 Answers2

2

I think I got it! Here's what I did:

Create a new JsonConverter: This will make sure that I will always get a list.

public class JsonAlbumConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.StartArray)
            return serializer.Deserialize<List<Album>>(reader);
        var itm = serializer.Deserialize<Album>(reader);
        return new List<Album> {itm};
    }

    public override bool CanConvert(Type objectType)
    {
        throw new NotImplementedException();
    }
}

Force the use of my converter by applying an attribute to the property

public class Albummatches
{
    [JsonProperty("Album")]
    [JsonConverter(typeof(JsonAlbumConverter))]
    public List<Album> Albums { get; set; }
}

It works but I was really hoping for a built-in solution, since I suspect this being a frequent issue...

Recipe
  • 1,398
  • 3
  • 16
  • 29
0

Make your single result a member with a set method, and override the set method to create a list and add the 1 item to it.

That handles your single and multiple results, and your code that uses the result only has to handle the multiple results.

For your example (this is psudeo code, I don't know the exact syntax)

Class Item
- List<ItemResult> Results { get; set; }
- ItemResult Result { set;}

Override the setter for the single result like:

setResult(ItemResult r){
    Results = new List<ItemResult>();
    Results.add(r);
}
mikeb
  • 10,578
  • 7
  • 62
  • 120
  • I'm trying to do this, but since the named Json property is Result, it will never try to set Results, not even when it is an array of ItemResult: hence it errors! – Recipe Aug 31 '14 at 14:58
  • I have updated my question with what I tried according to your suggestion. Didn't help :) – Recipe Aug 31 '14 at 15:04