3

I want to create an Windows Forms application that uses data from football-data.org. This is my first time I'm working with restful/JSON and I'm stuck.

When I try to get all of the leagues that football-data.org provides this is the response you get from the football-data.org api : response

I use the following code to get all of the data correct:(lbResultBox is a listbox)

private void btAllLeagues_Click(object sender, EventArgs e)
{
    lbResultBox.Items.Clear();
    List<Leagues> LL = GetLeagues("soccerseasons");
    foreach (var item in LL)
    {
       lbResultBox.Items.Add(item.caption);
    }
}

public static List<Leagues> GetLeagues(string endurl)
{
    var syncClient = new WebClient();
    var content = syncClient.DownloadString(baseurl + endurl);
    return JsonConvert.DeserializeObject<List<Leagues>>(content);
}

public class Leagues
{
    public IDictionary<string,LeagueLinks> _links { get; set; }
    public string caption { get; set; }
    public string league { get; set; }
    public string year { get; set; }
    public string numberOfTeams { get; set; }
    public string numberOfGames { get; set; }
    public string lastUpdated { get; set; }
}

public class LeagueLinks
{
    public string href { get; set; }
}

This works.

But when I try to get all the teams from a league this is the response i get from the api. I use this code:

private void btAllTeams_Click(object sender, EventArgs e)
{
    List<LeagueTeams> LT = GetLeagueTeams("soccerseasons/" + id + "/teams");
}

public static List<LeagueTeams> GetLeagueTeams(string endurl)
{
   var syncClient = new WebClient();
   var content = syncClient.DownloadString(baseurl + endurl);
   return JsonConvert.DeserializeObject<List<LeagueTeams>>(content);
}

public class LeagueTeams
{
    public IDictionary<string, LeagueLinks> _links { get; set; }
    public string count { get; set; }
    public IDictionary<string, LeagueTeam> teams { get; set; }
}

public class LeagueTeam
{
    public IDictionary<string, TeamLinks> _links { get; set; }
    public string name { get; set; }
    public string code { get; set; }
    public string shortName { get; set; }
    public string squadMarketValue { get; set; }
    public string crestUrl { get; set; }
}
public class TeamLinks
{
    public string href { get; set; }
}

But i get the following error:

An unhandled exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll Additional information: Cannot deserialize the current JSON array (e.g. [1,2,3]) into type System.Collections.Generic.IDictionary`2[System.String,FootballTestApplication.LeagueTeam]' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.

When i look at what the api give's me for response I can see a difference in how the response begins. With collecting all of the leagues it starts and ends with brackets ([]) but when collecting the teams in a league it doesn't start or end with brackets. When I Add the brackets myself I still get the error. This is how I add the brackets:

return JsonConvert.DeserializeObject<List<LeagueTeams>>("["+content+"]");

What am I doing wrong here?

John Saunders
  • 160,644
  • 26
  • 247
  • 397
RogierBa
  • 45
  • 2
  • 7
  • possible duplicate of [json newtonsoft : Deserialize Object containing a list of string](http://stackoverflow.com/questions/22580141/json-newtonsoft-deserialize-object-containing-a-list-of-string) – MethodMan May 12 '15 at 18:31

1 Answers1

1

The problem lies in the fact that the JSON returned is NOT an Array, List, Dictionary or other Enumerable but is instead an object of it's own.

If we take your JSON from that API link and go through it element by element, we learn that your Type is wrong.

You tell the JSON Serializer that the root object is a List<LeagueTeams>, but it is not. It is in fact a single LeagueTeams object.

If we make that modification to the deserializer, and we make a couple modifications to your LeagueTeams class (mostly the fact that you were deserializing the links property wrong), you are all set:

public class LeagueTeams
{
    public List<IDictionary<string, string>> _links { get; set; }
    public string count { get; set; }
    public List<LeagueTeam> teams { get; set; }
}

return JsonConvert.DeserializeObject<LeagueTeams>(content);

I've attached an image of the results.

Inspection of your Object

Additional Notes

Another thing to note: the JSON to C# website (http://json2csharp.com/) does NOT handle this JSON correctly, it in fact generates an object that is almost correct, but not quite. (Though, the generated object will still work properly, it is not an entirely correct mapping of the input JSON.) This is due, in part, to the fault of the generator, but also the website. It attempts to generate a list of a two-property Link element for the root links item, where it instead should have used a list of a dictionary to get correct mappings. (Though, this is a bit befuddling, it is the most correct approach.) Another thing to keep into consideration, yes, it does fine for getting a good start, but generally speaking, proper JSON handling requires more meticulous inspection of the generated objects to guarantee correctness.

Der Kommissar
  • 5,848
  • 1
  • 29
  • 43
  • This works! Thank you. I only have one question now. How can i add the "name" of a team in my listbox? because my foreach loop gets an getenumerator exception. – RogierBa May 12 '15 at 19:22
  • 1
    I just used the following code, and it did exactly that: `foreach (LeagueTeam team in obj.teams) { Console.WriteLine(team.name); /* Or other operation */ }` – Der Kommissar May 12 '15 at 19:23
  • Yes thanks i just wanted to update my questions because i found it. Thank you again. – RogierBa May 12 '15 at 19:25
  • @RogierBa Not a problem. Glad I could help. – Der Kommissar May 12 '15 at 19:26