Peter Centellini
Peter Centellini

Reputation: 1565

Deserialize nested json objects into c# objects

I have the following Json response:

{
  "Customers": [
    {
      "Customer": {
        "Address": {
          "City": "Stockholm",
          "PostalCode": "10123"
        },
        "Classifications": [
          "LoyaltyProgram",
          "Returning",
          "VeryImportant"
        ],
        "FirstName": "Peter",
        "LastName": "Centers",
        "Passport": {
          "Expiration": "2019-01-14",
          "Number": "1564931321655"
        },
      },
      "FirstName": "Peter",
      "LastName": "Centers",
      "Reservation": {
        "AdultCount": 2,
        "AssignedSpaceId": "03f59360-8644-4e29-927a-ad85a6514466",
      },
      "RoomNumber": "302"
    },
  ]
}

I have the following classes for every Customer:

public class CustomerDto
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public List<string> Classifications { get; set; }
    public PassportDto Passport { get; set; }
    public AddressDto Address { get; set; }
}

public class AddressDto
{
    public string City { get; set; }
    public string PostalCode { get; set; }
}

public class PassportDto
{
    public string Expiration { get; set; }
    public string Number { get; set; }
}

from this I use Json.Net and the following code from one of my methods (extract) where customers below is the response:

var jsonCustomers = JObject.Parse(customers)["Customers"].Children().ToList();
IList<CustomerDto> customerList = new List<CustomerDto>();
foreach (var item in jsonCustomers) {
    customerList.Add(item.ToObject<CustomerDto>());
}

All the values in CustomerDto are filled except for Address and Passport, that are null, and I can't figure out why.

Upvotes: 5

Views: 12270

Answers (3)

mjwills
mjwills

Reputation: 23819

Add two new classes:

public class CustomersWrapper
{
    public IEnumerable<CustomerWrapper> Customers { get; set; }
}

public class CustomerWrapper
{
    public CustomerDto Customer { get; set; }
}

and then replace all of your existing code with:

        var results = JsonConvert.DeserializeObject<CustomersWrapper>(input);
        var customerList = results.Customers.Select(z => z.Customer).ToList();

This will ensure that standard deserialisation occurs for all objects in the hierarchy.

This is needed due to the odd structure of your JSON. https://stackoverflow.com/a/45384366/34092 is the same basic issue (and may be worth a read) - essentially you shouldn't really have Customers and Customer in your JSON. Without those, you wouldn't need the two wrapper classes I have specified.

You may also wish to avoid specifying FirstName and LastName twice (unnecessarily) in the JSON.

Upvotes: 6

Marc Harry
Marc Harry

Reputation: 2430

You could create a class which has a list of customers on it:

public class CustomerList
{
    public IList<CustomerDto> Customers { get; set; }
}

And the to deserialize the object just call:

CustomerList jsonCustomers = JsonConvert.DeserializeObject<CustomerList>(customers);
IList<CustomerDto> customerList = jsonCustomers.Customers;

Edit: Didn't notice Customer was a nested property on the list of objects in the json array so need another class wrapping the CustomerDto. @mjwills has posted the full answer.

Upvotes: 5

Moim
Moim

Reputation: 486

The AddressDto and PassportDto will not be deserialized, just because you are deserializing at one level up in your JSON graph.

Write a class like:

public class WrapCustomer
{
        public CustomerDto Customer { get; set; }
}

Then deserialize this in your for-loop:

customerList.Add(item.ToObject<WrapCustomer>());

Now you will see everything is populated as you expected.

Upvotes: 2

Related Questions