Brandon James
Brandon James

Reputation: 83

How to Deserialize json that has properties containing different objects?

I'm currently working on a .NET client for the Zoho Books API in order to integrate some data within my organization. I have been struggling with deserializing the json returned by the API. The problem has been because of inheritance and varying property names. I think I'm looking at creating a custom converter in order to avoid creating response types for every model for the sake of a few varying fields.

I was able to create a custom converter that works for parent responses which look like this:

{
     "code" : 0,
     "message" : "success",
     "invoice" : { // This field varies by model
         "invoice_id" : "..."
     }
}

I have created a gist for this custom converter.

One of the issues with the custom converter is that when I pass the generic return type down from the web client, I need it in either in the base response format or the paginated response format, and generics are failing me here. My converter doesn't work for paginated responses.

I defined my base type of ZohoBooks Response as so:

namespace ZohoBooks4Net.Responses
{
    public class ZohoBooksResponse<T> : IZohoBooksResponse<T>
    {
        /// <summary>
        /// Zoho Books error code. This will be zero for a success response and non-zero in case of an error.
        /// </summary>

        [JsonProperty("code")]
        public int Code { get; set; }

        /// <summary>
        /// Message for the invoked API.
        /// </summary>

        [JsonProperty("message")]
        public string Message { get; set; }

        /// <summary>
        /// Comprises the invoked API’s Data.
        /// </summary>
        public T Resource { get; set; }
    }
}

Resource is what I'm calling the third field in the response.

However, when the response returns as paginated, it adds another field.

{
  "code": 0,
  "message": "success",
  "contacts": [
    { "..." }
  ],
  "page_context": {
    "page": 1,
    "per_page": 200,
    "has_more_page": false,
    "applied_filter": "Status.All",
    "sort_column": "contact_name",
    "sort_order": "D"
  }
}

So I created this object that describes it:

namespace ZohoBooks4Net.Responses.PaginatedResponses
{
    public class PaginatedResponse<T> : ZohoBooksResponse<T>, IPaginatedResponse<T>
    {
        [JsonProperty("page_context")]
        public PageContext Context { get; set; }
    }

    public class PageContext
    {
        [JsonProperty("page")]
        public int Page { get; set; }

        [JsonProperty("per_page")]
        public int PerPage { get; set; }

        [JsonProperty("has_more_page")]
        public bool HasMorePage { get; set; }
    }
}

If anyone has any solutions I would really appreciate it.

Upvotes: 2

Views: 470

Answers (3)

Brandon James
Brandon James

Reputation: 83

Taking a referenced post from a commenter, I implemented the ReadJson method created by poster of the article. This solved my issue. Here's a link to DynamicPropertyNameConverter on Github Gist.

Upvotes: 0

Suresh
Suresh

Reputation: 1083

Books already hosted .Net library in github. In Subscription java client, page context and resources handled separately.

Upvotes: 1

Rnice4christ
Rnice4christ

Reputation: 78

Have you tried using the json2csharp web application tool? It will create the classes needed from your JSON response and a root object which can be used with the Newtonsoft JsonCovnert's DeserializeObject method.

Upvotes: 0

Related Questions