Deserialize nested JSON Response with RestSharp Client

8.2k views Asked by At

I'd like to consume a REST Api and deserialize the nested JSON Response. For that purpose I tried to create some POCO classes which represent the JSON Response [1]. The response looks like this:

{
  "success": true,
  "message": "OK",
  "types": 
  [
    {
      "name": "A5EF3-ASR",
      "title": "ITIL Foundation Plus Cloud Introduction",
      "classroomDeliveryMethod": "Self-paced Virtual Class",
      "descriptions": {
        "EN": {
          "description": "some Text null",
          "overview": null,
          "abstract": "Some other text",
          "prerequisits": null,
          "objective": null,
          "topic": null
        }
      },
      "lastModified": "2014-10-08T08:37:43Z",
      "created": "2014-04-28T11:23:12Z"
    },
    {
      "name": "A4DT3-ASR",
      "title": "ITIL Foundation eLearning Course + Exam",
      "classroomDeliveryMethod": "Self-paced Virtual Class",
      "descriptions": {
        "EN": {
          "description": "some Text"
          (...)

So I created the following POCO classes:

public class Course
{
    public bool success { get; set; }
    public string Message { get; set; }
    public List<CourseTypeContainer> Type { get; set; }
}

/* each Course has n CourseTypes */
public class CourseType
{
    public string Name { get; set; }
    public string Title { get; set; }
    public List<CourseTypeDescriptionContainer> Descriptions { get; set; }
    public DateTime LastModified { get; set; }
    public DateTime Created { get; set; }
}
public class CourseTypeContainer
{
    public CourseType CourseType { get; set; }
}


/* each CourseType has n CourseTypeDescriptions */
public class CourseTypeDescription
{
    public string Description { get; set; }
    public string Overview { get; set; }
    public string Abstract { get; set; }
    public string Prerequisits { get; set; }
    public string Objective { get; set; }
    public string Topic { get; set; }
}
public class CourseTypeDescriptionContainer
{
    public CourseTypeDescription CourseTypeDescription { get; set; }
}

And this is the API Code:

var client = new RestClient("https://www.someurl.com");
client.Authenticator = new HttpBasicAuthenticator("user", "password");

var request = new RestRequest();
request.Resource = "api/v1.0/types";
request.Method = Method.GET;
request.RequestFormat = DataFormat.Json;

var response = client.Execute<Course>(request);

EDIT 1: I found a Typo, the Type property in AvnetCourse should be named Types:

public List<AvnetCourseTypeContainer> Type { get; set; }    // wrong
public List<AvnetCourseTypeContainer> Types { get; set; }   // correct

Now the return values look like:

response.Data.success = true                    // CORRECT
repsonse.Data.Message = "OK"                    // CORRECT
response.Data.Types = (Count: 1234);            // CORRECT
response.Data.Types[0].AvnetCourseType = null;  // NOT CORRECT

EDIT 2: I implemented the Course.Types Property using a List<CourseType> instead of a List<CourseTypeContainer>, as proposed by Jaanus. The same goes for the CourseTypeDescriptionContainer:

public List<CourseTypeContainer> Type { get; set; }                     // OLD
public List<CourseTypeDescriptionContainer> Descriptions { get; set; }  // OLD
public List<CourseType> Type { get; set; }                              // NEW
public List<CourseTypeDescription> Descriptions { get; set; }           // NEW

Now the response.Data.Types finally are properly filled. However, the response.Data.Types.Descriptions are still not properly filled, since there is an additional language layer (e.g. "EN"). How can I solve this, without creating a PACO for each language?

EDIT 3: I had to add an additional CourseTypeDescriptionDetails class, where I would store the descriptive Data. In my CourseTypeDescription I added a property of the Type List for each language. Code Snippet:

public class AvnetCourseType
{
    public List<CourseTypeDescription> Descriptions { get; set; }
    // other properties
}
public class CourseTypeDescription
{
    public List<CourseTypeDescriptionDetails> EN { get; set; } // English
    public List<CourseTypeDescriptionDetails> NL { get; set; } // Dutch
}
public class CourseTypeDescriptionDetails
{
    public string Description { get; set; }
    public string Overview { get; set; }
    public string Abstract { get; set; }
    public string Prerequisits { get; set; }
    public string Objective { get; set; }
    public string Topic { get; set; }
}

It works now, but I need to add another property to CourseTypeDescription for each language.

OLD: The return values are

response.Data.success = true            // CORRECT
repsonse.Data.Message = "OK"            // CORRECT
response.Data.Type = null;              // WHY?

So why does my response.Type equal null? What am I doing wrong?

Thank you

Resources: [1] RestSharp Deserialization with JSON Array

3

There are 3 answers

6
Jaanus On BEST ANSWER

Try using this as POCO:

public class Course
{
    public bool success { get; set; }
    public string message { get; set; }
    public List<CourseTypeContainer> Types { get; set; }
}

Now you have list of CourseTypeContainer. And CourseTypeContainer is

public class CourseTypeContainer
{
    public CourseType CourseType { get; set; }
}

So when you are trying to get response.Data.Types[0].AvnetCourseType , then you need to have field AvnetCourseType inside CourseTypeContainer

Or I think what you want is actually this public List<CourseType> Types { get; set; }, you don't need a container there.

0
Jordan Ryder On

Just in case this helps someone else, I tried everything here and it still didn't work on the current version of RestSharp (106.6.2). RestSharp was completely ignoring the RootElement property as far as I could tell, even though it was at the top level. My workaround was to manually tell it to pull the nested JSON and then convert that. I used JSON.Net to accomplish this.

var response = restClient.Execute<T>(restRequest);
response.Content = JObject.Parse(response.Content)[restRequest.RootElement].ToString();
return new JsonDeserializer().Deserialize<T>(response);
0
Gurunadh Duvvuru On

I used http://json2csharp.com/ to create C# classes from JSON. Then, renamed RootObject to the ClassName of the model file I'm creating All the data in the nested json was accessible after RestSharp Deserializitaion similar to responseBody.data.Subject.Alias where data, Subject and Alias are nested nodes inside the response JSON received.