0
votes

I am trying to call an API with HttpClient and deserialize the json to a response object. In this json, there is a list of trivia question objects. When I set the object to the deserialized object, the list stays empty.

I've checked if HttpClient works, it does, I also tried using JsonConvert.

These are the TriviaQuestion and Response classes:

public class TriviaQuestion
{
    public string Category { get; set; }
    public string Type { get; set; }
    public string Difficulty { get; set; }
    public string Question { get; set; }
    public string CorrectAnswer { get; set; }
    public List<string> IncorrectAnswers { get; set; }

    public override string ToString()
    {
        return $"Question: {Question}";
    }
}

public class Response
{
    public int ResponseCode { get; set; }
    public List<TriviaQuestion> Questions { get; set; }

    public Response()
    {
        Questions = new List<TriviaQuestion>();
    }
}

This is the code for deserializing

private static HttpClient client = new HttpClient();
private static string URL = "https://opentdb.com/api.php";
private static string urlParameters = "?amount=1";

static void Main()
{
    RunAsync().GetAwaiter().GetResult();
}

static async Task RunAsync()
{
    client.BaseAddress = new Uri(URL);
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(
       new MediaTypeWithQualityHeaderValue("application/json"));

    Response response = new Response();

    try
    {
        response = await GetResponseAsync(urlParameters);
        ShowResponse(response);
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }

    Console.ReadLine();
}

static async Task<Response> GetResponseAsync(string path)
{
    Response response = new Response();
    //string responseString = "";

    HttpResponseMessage httpResponse = await client.GetAsync(path);

    if (httpResponse.IsSuccessStatusCode)
    {
        //responseString = httpResponse.Content.ReadAsStringAsync().Result;
        response = await httpResponse.Content.ReadAsAsync<Response>();
    }

    //response = JsonConvert.DeserializeObject<Response>(responseString);
    return response;
}

I expect to get a list of trivia question objects, but the list stays on count = 0. If I print out the jsonString I'm getting this is the result:

{
    "response_code":0,
    "results": [
    { 
        "category":"Entertainment: Video Games",
        "type":"multiple",
        "difficulty":"medium",
        "question":"In Need for Speed: Underground, what car does Eddie drive?",
        "correct_answer":"Nissan Skyline GT-R (R34)",
        "incorrect_answers": [
            "Mazda RX-7 FD3S",
            "Acura Integra Type R",
            "Subaru Impreza 2.5 RS"
        ]
    }]
}

Thanks for helping!

2
You'll need to post a sample of the JSON that you actually receive, it's likely you just need to change the model but we can't know without seeing the JSON string. - JSteward
I edited it, added an example json string - Nard Swolfs

2 Answers

1
votes

Your Response class is slightly wrong. It does not match the JSON you posted.

public List<TriviaQuestion> Questions { get; set; }

should be:

public List<TriviaQuestion> Results { get; set; }

Additionally, as your JSON has snake casing, to capture the response_code, correct_answer and incorrect_answers values you will need to either decorate your class properties with JsonProperty attributes i.e. [JsonProperty(PropertyName = "incorrect_answers")] or you can use a ContractResolver:

var contractResolver = new DefaultContractResolver
{
    NamingStrategy = new SnakeCaseNamingStrategy()
};

var response = JsonConvert.DeserializeObject<Response>(json, new JsonSerializerSettings
{
    ContractResolver = contractResolver
});

So your full classes would be:

public class TriviaQuestion
{
    public string Category { get; set; }

    public string Type { get; set; }

    public string Difficulty { get; set; }

    public string Question { get; set; }

    // only need this if not using the ContractResolver
    [JsonProperty(PropertyName = "correct_answer")]
    public string CorrectAnswer { get; set; }

    // only need this if not using the ContractResolver
    [JsonProperty(PropertyName = "incorrect_answers")]
    public List<string> IncorrectAnswers { get; set; }
}

public class Response
{
    // only need this if not using the ContractResolver
    [JsonProperty(PropertyName = "response_code")]  
    public int ResponseCode { get; set; }

    public List<TriviaQuestion> Results { get; set; }
}

Then you will be able to deserialize:

var json = "{\r\n    \"response_code\":0,\r\n    \"results\": [\r\n    { \r\n        \"category\":\"Entertainment: Video Games\",\r\n        \"type\":\"multiple\",\r\n        \"difficulty\":\"medium\",\r\n        \"question\":\"In Need for Speed: Underground, what car does Eddie drive?\",\r\n        \"correct_answer\":\"Nissan Skyline GT-R (R34)\",\r\n        \"incorrect_answers\": [\r\n            \"Mazda RX-7 FD3S\",\r\n            \"Acura Integra Type R\",\r\n            \"Subaru Impreza 2.5 RS\"\r\n        ]\r\n    }]\r\n}";

// if using JsonProperty attributes
var response = JsonConvert.DeserializeObject<Response>(json);

// or 

// if using ContractResolver
var contractResolver = new DefaultContractResolver
{
    NamingStrategy = new SnakeCaseNamingStrategy()
};

var response = JsonConvert.DeserializeObject<Response>(json, new JsonSerializerSettings
{
    ContractResolver = contractResolver
});
0
votes

the returned JSON into a Response:

var json = await httpResponse.Content.ReadAsStringAsync();
response= JsonConvert.DeserializeObject<Response>(json);