将嵌套的JSON对象反序列化为C#对象

5

我有以下Json响应:

{
  "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"
    },
  ]
}

每个客户都有以下类:

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; }
}

我使用Json.Net和以下代码中的一个方法(extract)从客户端获取响应数据,具体代码如下:

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

客户传输对象(CustomerDto)中的所有值都已填写,除了地址和护照是空的,我无法弄清原因。

3个回答

6
添加两个新类:
public class CustomersWrapper
{
    public IEnumerable<CustomerWrapper> Customers { get; set; }
}

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

然后用以下代码替换您现有的所有代码:

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

这样可以确保在层级结构中的所有对象进行标准反序列化。
由于您的JSON的奇怪结构,这是必需的。 https://stackoverflow.com/a/45384366/34092 是同样的基本问题(可能值得一读)- 本质上您不应该在JSON中有CustomersCustomer。如果没有这些,您就不需要我指定的两个包装类。
您也可以避免在JSON中不必要地指定FirstNameLastName两次。

是的,我没有关注FirstName和LastName的外部值,只是获取“Customers”。 - Peter Centellini
是的,它完美地运行了,谢谢。 :) 这个 Json 响应来自另一个来源/公司(一个在线酒店预订系统),我无法控制代码。我同意这个 Json 响应看起来有点奇怪,当被问及时,他们说这是由于向后兼容性而导致的。 - Peter Centellini

5

您可以创建一个类,其中包含客户列表:

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

要反序列化对象,只需调用:

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

编辑:没有注意到客户是JSON数组中对象列表上的嵌套属性,因此需要另一个包装CustomerDto的类。@mjwills已发布完整答案。


这是一个不错的代码示例,但并没有解决所提出的问题。添加此代码仍将导致地址和护照设置为无(空)。 - Moim
是的,我刚意识到我在JSON结构方面漏掉了一些东西,@mjwills已经更新了他们的答案并提供了正确的答案。 - Marc Harry

2

AddressDtoPassportDto不会被反序列化,因为您在JSON图形的上一级进行了反序列化。

编写一个类如下:

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

然后在您的for循环中反序列化:

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

现在,您会发现所有内容都按照您的预期填充。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接