Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSON.net deserialize object nested data

I'm working with SwiftType Elastic Search + C# and running into an issue deserializing the response due to the fact that SwiftType returns all of the fields as objects with a raw property (https://swiftype.com/documentation/app-search/api/search) for example:

{
  "meta": {
    "warnings": [],
    "page": {
      "current": 1,
      "total_pages": 1,
      "total_results": 2,
      "size": 10
    },
    "request_id": "6887a53f701a59574a0f3a7012e01aa8"
  },
  "results": [
    {
      "phone": {
        "raw": 3148304280.0
      },
      "accounts_balance_ach": {
        "raw": 27068128.71
      },
      "accounts_balance_pending": {
        "raw": "46809195.64"
      },
      "email": {
        "raw": "[email protected]"
      },
      "accounts_count": {
        "raw": 6.0
      },
      "id": {
        "raw": "c98808a2-d7d6-4444-834d-2fe4f6858f6b"
      },
      "display_name": {
        "raw": "The Johnstons"
      },
      "type": {
        "raw": "Couple"
      },
      "advisor_email": {
        "raw": "[email protected]"
      },
      "created_at": {
        "raw": "2018-10-02T10:42:07+00:00"
      },
      "source": {
        "raw": "event"
      },
      "accounts_balance": {
        "raw": 43629003.47
      },
      "accounts_donations": {
        "raw": 38012278.75
      },
      "advisor_name": {
        "raw": "Cloyd Jakubowski"
      },
      "_meta": {
        "score": 0.42934617
      }
    },
    {
      "phone": {
        "raw": 2272918612.0
      },
      "accounts_balance_ach": {
        "raw": 35721452.35
      },
      "accounts_balance_pending": {
        "raw": "35117465.2"
      },
      "email": {
        "raw": "[email protected]"
      },
      "accounts_count": {
        "raw": 1.0
      },
      "id": {
        "raw": "687af11f-0f73-4112-879c-1108303cb07a"
      },
      "display_name": {
        "raw": "Kennith Johnston"
      },
      "type": {
        "raw": "Individual"
      },
      "advisor_email": {
        "raw": "[email protected]"
      },
      "created_at": {
        "raw": "2018-10-02T16:16:02+00:00"
      },
      "source": {
        "raw": "website"
      },
      "accounts_balance": {
        "raw": 23063874.19
      },
      "accounts_donations": {
        "raw": 33025175.79
      },
      "advisor_name": {
        "raw": "Ernie Mertz"
      },
      "_meta": {
        "score": 0.39096162
      }
    }
  ]
}

I need to map each key to its value, eg results[0].email = "[email protected]";

I saw a promising option with custom converters but I want to make sure there is not a more dynamic way to do this before I take the verbose approach.

like image 421
ForrestLyman Avatar asked Oct 03 '18 03:10

ForrestLyman


2 Answers

I would suggest using the JsonPathConverter class found in Can I specify a path in an attribute to map a property in my class to a child property in my JSON?. This will allow you to declare a strongly-typed Result class and then easily map each of the properties to the value of the respective raw child value in the JSON without having to declare a ton of awkward single-property classes.

Declare your model as shown below. Note that the Result class needs a [JsonConverter] attribute on it to tie it to the JsonPathConverter (otherwise the property paths will not work and you will get default values in your properties).

public class RootObject
{
    public List<Result> results { get; set; }
}

[JsonConverter(typeof(JsonPathConverter))]
public class Result
{
    [JsonProperty("phone.raw")]
    public string Phone { get; set; }

    [JsonProperty("accounts_balance_ach.raw")]
    public decimal AccountsBalanceAch { get; set; }

    [JsonProperty("accounts_balance_pending.raw")]
    public decimal AccountsBalancePending { get; set; }

    [JsonProperty("email.raw")]
    public string Email { get; set; }

    [JsonProperty("accounts_count.raw")]
    public decimal AccountsCount { get; set; }

    [JsonProperty("id.raw")]
    public string Id { get; set; }

    [JsonProperty("display_name.raw")]
    public string DisplayName { get; set; }

    [JsonProperty("type.raw")]
    public string Type { get; set; }

    [JsonProperty("advisor_email.raw")]
    public string AdvisorEmail { get; set; }

    [JsonProperty("created_at.raw")]
    public string CreatedAt { get; set; }

    [JsonProperty("source.raw")]
    public string Source { get; set; }

    [JsonProperty("accounts_balance.raw")]
    public decimal AccountsBalance { get; set; }

    [JsonProperty("accounts_donations.raw")]
    public decimal AccountsDonations { get; set; }

    [JsonProperty("advisor_name.raw")]
    public string AdvisorName { get; set; }

    [JsonProperty("_meta.score")]
    public decimal MetaScore { get; set; }
}

Then you can just deserialize as usual:

var root = JsonConvert.DeserializeObject<RootObject>(json);

Here is a working demo: https://dotnetfiddle.net/wYxwIF

like image 149
Brian Rogers Avatar answered Oct 27 '22 13:10

Brian Rogers


The Most dynamic way for you would be to use The Newtonsoft JObejct class.

It will parse your JSON string into a JSON object for you to use, this is if you do not have a corresponding model and you need to create a dynamic JSON object.

For example:

string json = "{
  "meta": {
    "warnings": [],
    "page": {
      "current": 1,
      "total_pages": 1,
      "total_results": 2,
      "size": 10
    },
    "request_id": "6887a53f701a59574a0f3a7012e01aa8"
  },
  "results": [
    {
      "phone": {
        "raw": 3148304280.0
      },
      "accounts_balance_ach": {
        "raw": 27068128.71
      },
      "accounts_balance_pending": {
        "raw": "46809195.64"
      },
      "email": {
        "raw": "[email protected]"
      },
      "accounts_count": {
        "raw": 6.0
      },
      "id": {
        "raw": "c98808a2-d7d6-4444-834d-2fe4f6858f6b"
      },
      "display_name": {
        "raw": "The Johnstons"
      },
      "type": {
        "raw": "Couple"
      },
      "advisor_email": {
        "raw": "[email protected]"
      },
      "created_at": {
        "raw": "2018-10-02T10:42:07+00:00"
      },
      "source": {
        "raw": "event"
      },
      "accounts_balance": {
        "raw": 43629003.47
      },
      "accounts_donations": {
        "raw": 38012278.75
      },
      "advisor_name": {
        "raw": "Cloyd Jakubowski"
      },
      "_meta": {
        "score": 0.42934617
      }
    },
    {
      "phone": {
        "raw": 2272918612.0
      },
      "accounts_balance_ach": {
        "raw": 35721452.35
      },
      "accounts_balance_pending": {
        "raw": "35117465.2"
      },
      "email": {
        "raw": "[email protected]"
      },
      "accounts_count": {
        "raw": 1.0
      },
      "id": {
        "raw": "687af11f-0f73-4112-879c-1108303cb07a"
      },
      "display_name": {
        "raw": "Kennith Johnston"
      },
      "type": {
        "raw": "Individual"
      },
      "advisor_email": {
        "raw": "[email protected]"
      },
      "created_at": {
        "raw": "2018-10-02T16:16:02+00:00"
      },
      "source": {
        "raw": "website"
      },
      "accounts_balance": {
        "raw": 23063874.19
      },
      "accounts_donations": {
        "raw": 33025175.79
      },
      "advisor_name": {
        "raw": "Ernie Mertz"
      },
      "_meta": {
        "score": 0.39096162
      }
    }
  ]
}"

JObject result = JObject.Parse(json);

result is now a JSON object and you can access it's properties.

like image 30
Barr J Avatar answered Oct 27 '22 15:10

Barr J