Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c# Generic data object using newtonsofts JsonConvert DeserializeObject

Tags:

json

c#

json.net

We are using an external API that returns its results using the object name "Data". This "Data" can represent two different objects -one in the form of an json object array and another int the form of a single json object.

I have a created two separate c# classes that represents the JSON object data and a c# root object class to capture the JSON objects when being converted using JsonConvert.DeserializeObject...How would one go about representing these objects correctly in C# see below examples of results:

below is example of 1 resulting API Call

{
success:true,
Data:[{id:1,name:"Paul"},{id:2,name:"neville"},{id:3,name:"jason"}]
}

public class User
{
    public int id { get; set; }
    public string name { get; set; }
}

public class ApiResponse
{
    public bool success { get; set; }
    public List<User> Data { get; set; }
}

Below is example 2 of resulting API call

{
    success:true,
    Data:{id:1,classSize:30,minAge:25, maxAge:65}
}
public class AgeClass
{
    public int id { get; set; }
    public int classSize { get; set; }
    public int minAge { get; set; }
    public int maxAge { get; set; }
}

public class ApiResponse
{
    public bool success { get; set; }
    public AgeClass Data { get; set; }
}

How would I construct the ApiResponse Class to cater for the Generic "Data" object json string returned - so that I can use the generic "JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync(), Settings);"

like image 516
Paul Avatar asked Jan 28 '19 09:01

Paul


Video Answer


2 Answers

You could just make your class generic by adding generic type parameter for Data property:

public class ApiResponse<T>
{
    public bool success { get; set; }
    public T Data { get; set; }
}

And then use it when deserializing:

  var result = JsonConvert.DeserializeObject<ApiResponse<AgeClass>>(myJson ...);
  var result = JsonConvert.DeserializeObject<ApiResponse<List<User>>>(myJson ...);
like image 36
Fabjan Avatar answered Sep 22 '22 10:09

Fabjan


I would propose to consider you actually have 2 types of JSON response. You also can inherit them from base ApiResponse class:

using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            string json1 = @"{
                                ""success"":true,
                                ""Data"":[{id:1, name:""Paul""},{id:2,name:""neville""},{id:3,name:""jason""}]
                            }";

            string json2 = @"{
                                ""success"":true,
                                ""Data"":{id:1,classSize:30,minAge:25, maxAge:65}
                             }";

            string j = json1; //json2;

            JObject jo = JObject.Parse(j);

            ApiResponse parsed;

            if (jo["Data"].Type == JTokenType.Array)
                parsed = jo.ToObject<ApiUsersResponse>();
            else
                parsed = jo.ToObject<ApiAgeResponse>();

            Console.ReadKey();
        }        
    }

    class User
    {
        public int id { get; set; }
        public string name { get; set; }
    }

    class AgeClass
    {
        public int id { get; set; }
        public int classSize { get; set; }
        public int minAge { get; set; }
        public int maxAge { get; set; }
    }

    class ApiResponse
    {
        public bool success { get; set; }
    }

    class ApiUsersResponse : ApiResponse
    {
        public List<User> Data { get; set; }
    }

    class ApiAgeResponse : ApiResponse
    {            
        public AgeClass Data { get; set; }
    }     
}
like image 176
Vladimir P. Avatar answered Sep 22 '22 10:09

Vladimir P.