3

I have an API I am receiving data from. That API is out of my control on how it is structured, and I need to serialize and deserialize the JSON output to map the data to my model.

Everything works well where JSON is nicely formatted with named properties.

What can you do where there is no named value and there is just an array of ints and strings? like under locations

here is a sample of the JSON:

{"id":"2160336","activation_date":"2013-08-01","expiration_date":"2013-08-29","title":"Practice Manager","locations":{"103":"Cambridge","107":"London"}}

I have models that are like:

public class ItemResults
{
    public int Id { get; set; }

    public DateTime Activation_Date { get; set; }

    public DateTime Expiration_Date{ get; set; } 

    public string Title { get; set; }

    public Location Locations { get; set; }
}

public class Location
{
    public int Id { get; set; }

    public string value { get; set; }
}

and I am mapping using the inbuilt ajax serialization:

 protected T MapRawApiResponseTo<T>( string response )
    {
        if ( string.IsNullOrEmpty( response ) )
        {
            return default( T );
        }

        var serialize = new JavaScriptSerializer();

        return serialize.Deserialize<T>( response );
    }

var results = MapRawApiResponseTo<ItemResults>(rawApiResponse);

So the ID and all other properties are picked up and mapped but what every I do I can not seem to map the locations.

Many thanks

Fuzzybear
  • 1,388
  • 2
  • 25
  • 42
  • 2
    Shouldn't the field in your `ItemResults` class be a collection and named plural? e.g. `public IEnumerable Locations { get; set; }` – Brad Rem Aug 14 '13 at 13:32
  • 4
    As with a lot of JSON questions involving `JavaScriptSerializer`, the first part of any answer should usually be "stop using `JavaScriptSerializer`"; sorry, but for anything even remotely non-trivial, Json.NET does a *much* better job – Marc Gravell Aug 14 '13 at 13:37
  • 1
    Removed my answer as the format didn't come out well, but this is a useful site for seeing how to structure your classes: http://json2csharp.com/ – stevepkr84 Aug 14 '13 at 13:38

4 Answers4

2
public Dictionary<int,string> Locations { get; set; }

job done; you should find that using Json.NET, at least, i.e.

var result = JsonConvert.DeserializeObject<ItemResults>(json);

you get 2 entries in result.Locations; specifically result[103] = "Cambridge"; and result[107] = "London";

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
2

If you don't mind, you can workaround with dictionary:

class Program
{
    static void Main(string[] args)
    {
        string json =
            "{'id':'2160336','activation_date':'2013-08-01','expiration_date':'2013-08-29','title':'Practice Manager','locations':{'103':'Cambridge','107':'London'}}";
        var deserializeObject = JsonConvert.DeserializeObject<ItemResults>(json);
        Console.WriteLine("{0}:{1}", deserializeObject.Locations.First().Key, deserializeObject.Locations.First().Value);
        Console.ReadKey();
    }
}

public class ItemResults
{
    public int Id { get; set; }
    public DateTime Activation_Date { get; set; }
    public DateTime Expiration_Date { get; set; }
    public string Title { get; set; }
    public Dictionary<int, string> Locations { get; set; }
}

you can also use manual parsing, like here: Json.NET (Newtonsoft.Json) - Two 'properties' with same name?

Community
  • 1
  • 1
Giedrius
  • 8,430
  • 6
  • 50
  • 91
1

This will work:

public Dictionary<string, string> Locations { get; set; }

public IEnumerable<Location> LocationObjects { get { return Locations
     .Select(x => new Location { Id = int.Parse(x.Key), value = x.Value }); } }
Tim S.
  • 55,448
  • 7
  • 96
  • 122
1

I propose you the following solution :

public class ItemResults
{
    public int Id { get; set; }

    public DateTime Activation_Date { get; set; }

    public DateTime Expiration_Date { get; set; }

    public string Title { get; set; }

    [JsonProperty("locations")]
    public JObject JsonLocations { get; set; }

    [JsonIgnore]
    public List<Location> Locations { get; set; }

    [OnDeserialized]
    public void OnDeserializedMethod(StreamingContext context)
    {
        this.Locations = new List<Location>();
        foreach (KeyValuePair<string, JToken> item in this.JsonLocations)
        {
            this.Locations.Add(new Location() { Id = int.Parse(item.Key), value = item.Value.ToString() });
        }
    }
}

public class Location
{
    public int Id { get; set; }

    public string value { get; set; }
}

After you just have to deserialize your JSON with : JsonConvert.DeserializeObject<ItemResults>(json);

Joffrey Kern
  • 6,449
  • 3
  • 25
  • 25
  • Compared to just using a `Dictionary`, that is doing things the hard way, just a bit...? – Marc Gravell Aug 14 '13 at 13:51
  • 1
    If a location is juste an id with a value, so yes, it's hard way. But if have more properties (geolocatiion, complete address, etc...), this way could help :) – Joffrey Kern Aug 14 '13 at 13:56