Jamesits
Jamesits

Reputation: 642

Deserialize JSON with variable property name and nested list to object

I have a bunch of API which generates the following 2 kinds of reply in response body:

{ "error": null, "object_type": { /* some object */ } }
{ "error": null, "object_type": [{ /* some object */ }, { /* some object */ }, ...] }

While I have a class corresponding to the object structure, I want to deserialize the API endpoints directly into either an object of the class or a List<class>, without creating some "result" classes to match the response JSON structure. Is this possible?

For example there is 2 API:

/api/getAllCompanies

returns

{ "error": null, "company": [ { "name": "Microsoft", "country": "US" }, { "name": "Apple", "country": "US" } ]

while

/api/getUserCompany

returns

{ "error": null, "company": { "name": "Microsoft", "country": "US" } }

I have a class in code:

public class Company {
    string Name { get; set; }
    string Country { get; set; }
}

How can I directly deserialize the data into a Company object or a List<Company> without creating a bunch of other class?

(The JSON property name (company) is known so don't need to extract it elsewhere.)

I've been trying to first deserialize the response JSON into an ExpandoObject then copy the properties to an instance of destination class using the code here then convert it using the following code, but this seems not to work with lists.

private static async Task<T> GetApiObject<T>(string api, string extractedObjName) where T: class, new()
    {
        var retstr = await /* get API response as string */;
        dynamic retobj = JsonConvert.DeserializeObject<ExpandoObject>(retstr, new ExpandoObjectConverter());
        var ret = new T();
        Mapper<T>.Map((ExpandoObject)((IDictionary<string, object>)retobj)[extractedObjName], ret);
        return ret;
    }

Upvotes: 1

Views: 1118

Answers (1)

Ray Krungkaew
Ray Krungkaew

Reputation: 6965

You can use JObejct to extract the information you need before deserialize it into the object.

var str = "{ \"error\": null, \"company\": [{ \"name\": \"Microsoft\", \"country\": \"US\" } ,{ \"name\": \"Apple\", \"country\": \"US\" } ]}";
var temp = JObject.Parse(str).GetValue("company");
var companies = temp.Select(x => x.ToObject<Company>()).ToList();

Same goes for /api/getUserCompany

var str = "{ \"error\": null, \"company\": { \"name\": \"Microsoft\", \"country\": \"US\" } }";
var temp = JObject.Parse(str).GetValue("company");
var company = temp.ToObject<Company>();

Upvotes: 1

Related Questions