Десериализовать объект JSON во вложенный объект C # - PullRequest
0 голосов
/ 25 июня 2018

Редактировать : Полагаю, я должен упомянуть, что у меня нет контроля над JSON, и я знаю, что обычно мой объект C # должен соответствовать JSON.Мой вопрос не был «почему это не десериализация?».Я знаю, почему это не так.Я спрашиваю, есть ли способ десериализации JSON, как я спрашиваю.

Я использую Newtonsoft.Json.

У меня есть строка JSON, содержащая 1 объект.Мне нужно десериализовать этот объект в объект C # с вложенным объектом.

Итак, допустим, мой JSON выглядит следующим образом.

{
    "id": 123,
    "userName": "fflintstone",
    "address": "345 Cave Stone Road",
    "address2": "",
    "city": "Bedrock",
    "state": "AZ",
    "zip": "",   
}

А вот мой объект C #

public class Customer
{
    public long Id { get; set; }

    public string UserName { get; set; }

    public AddressModel Address { get; set; }
}

Свойство AddressModel Address является вложенным объектом.Этот объект содержит фактические свойства адреса.Поэтому мне нужно десериализовать мой объект JSON, чтобы id и userName добавлялись в объект Customer, а затем поля адреса добавлялись во вложенный объект Address.

Мне не удалось найти способ, который встроен в newtonsoft, чтобы добиться этого.Есть идеи?

Ответы [ 5 ]

0 голосов
/ 25 июня 2018

Вы можете сделать это с помощью пользовательского JsonConverter.

public class CustomerJsonConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        if (value is Customer customer)
        {
            var token = new JObject
            {
                ["id"] = customer.Id,
                ["userName"] = customer.UserName,
                ["address"] = customer.Address.Address,
                ["address2"] = customer.Address.Address2,
                ["city"] = customer.Address.City,
                ["state"] = customer.Address.State,
                ["zip"] = customer.Address.ZIP
            };

            token.WriteTo(writer);
        }
        else
        {
            throw new InvalidOperationException();
        }

    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var obj = JToken.ReadFrom(reader);

        if (obj.Type != JTokenType.Object)
        {
            return null;
        }

        return new Customer
        {
            Id = (long) obj["id"],
            UserName = (string) obj["userName"],
            Address = obj.ToObject<AddressModel>()
        };
    }

    public override bool CanRead => true;

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Customer);
    }
}

Вместе с JsonConverterAttribute для класса Customer.

[JsonConverter(typeof(CustomerJsonConverter))]
public class Customer
{
    public long Id { get; set; }

    public string UserName { get; set; }

    public AddressModel Address { get; set; }
}

public class AddressModel
{
    public string Address { get; set; }

    public string Address2 { get; set; }

    public string City { get; set; }

    public string State { get; set; }

    public string ZIP { get; set; }
}

И использовать как таковой:

var customer = JsonConvert.DeserializeObject<Customer>(customerJson);

альтернативно, вы могли бы просто иметь промежуточную модель отображения.

public class CustomerFlattened
{
    public long Id { get; set; }

    public string UserName { get; set; }

    public string Address { get; set; }

    public string Address2 { get; set; }

    public string City { get; set; }

    public string State { get; set; }

    public string ZIP { get; set; }

    public Customer ToCustomer()
    {
        return new Customer
        {
            Id = Id,
            UserName = UserName,
            Address = new AddressModel
            {
                Address = Address,
                Address2 = Address2,
                City = City,
                State = State,
                ZIP = ZIP
            }
        };
    }

    public static CustomerFlattened FromCustomer(Customer customer)
    {
        return new CustomerFlattened
        {
            Id = customer.Id,
            UserName = customer.UserName,
            Address = customer.Address.Address,
            Address2 = customer.Address.Address2,
            City = customer.Address.City,
            State = customer.Address.State,
            ZIP = customer.Address.ZIP
        };
    }
}

И использовать как таковой:

var customer =
    JsonConvert.Deserialize<CustomerFlattened>(
        jsonOriginal
    )
    .ToCustomer();

var customerFlattened = CustomerFlattened.FromCustomer(customer);

var jsonConverted = JsonConvert.Serialize(customerFlattened );
0 голосов
/ 25 июня 2018

Поскольку ваш JSON и ваша объектная модель не совпадают, вам придется десериализовать временный объект и сопоставить поля самостоятельно. В этом примере я десериализую анонимный объект, который используется как шаблон.

//This is our test data
var input = @"{
    ""id"": 123,
    ""userName"": ""fflintstone"",
    ""address"": ""345 Cave Stone Road"",
    ""address2"": """",
    ""city"": ""Bedrock"",
    ""state"": ""AZ"",
    ""zip"": """"   
}";

//This anonymous type will be used as a template to deserialize the test data
var template = new 
{ 
    id = default(int),
    userName = default(string),
    address = default(string),
    address2 = default(string),
    city = default(string),
    state = default(string),
    zip = default(string)
};

//Deserialize
var temp = JsonConvert.DeserializeAnonymousType(input, template);

//Use the deserialized object to create an AddressModel
var address = new AddressModel
{
    Address = temp.address,
    Address2 = temp.address,
    City = temp.city,
    State = temp.state,
    Zip = temp.zip
};

//Create a customer using the deserialized data and our new AddressModel instance
var customer = new Customer
{
    Id = temp.id,
    UserName = temp.userName,
    Address = address
};

//Output a couple fields to check
Console.WriteLine("{0} {1}", customer.Id, customer.Address.City);

Выход:

123 Bedrock

Рабочий пример для DotNetFiddle

0 голосов
/ 25 июня 2018

Если вы хотите использовать дополнительный инструмент, вы можете создать DTO, соответствующий JSON, а затем использовать сопоставитель, такой как Automapper, для обратного сглаживания DTO в вашей объектной модели.

0 голосов
/ 25 июня 2018

Сначала для объекта, который вы хотите создать с помощью класса AdressModel, вам нужно изменить свой документ JSON, я изменил на:

  {   "id": 123,   "userName": "fflintstone",   "Address": {
"address": "345 Cave Stone Road",
"address2": "",
"city": "Bedrock",
"state": "AZ",
"zip": ""   } }

Затем для моделей, которые я создал, две эти модели:

public class Customer
{
    public long id { get; set; }
    public string userName { get; set; }
    public AddressModel Address { get; set; }
}

public class AddressModel
{
    public string address { get; set; }
    public string address2 { get; set; }
    public string city { get; set; }
    public string state { get; set; }
    public string zip { get; set; }
}

Теперь для десериализации документа Json вы можете сделать что-то вроде этого:

Customer jsonConverted = new Customer();

        using (StreamReader r = new StreamReader(HostingEnvironment.ApplicationPhysicalPath + @"\infoFile.json"))
        {
            var json = r.ReadToEnd();
            jsonConverted = JsonConvert.DeserializeObject<Customer>(json);
        }

(я тестирую с проектом MVC) enter image description here

0 голосов
/ 25 июня 2018

Если вы настраиваете JSON, который будет использоваться вашим кодом, то ваш JSON не настроен так, чтобы соответствовать вашему объекту.

Он должен выглядеть следующим образом:

{
    "id": 123,
    "userName": "fflintstone",
    "address": {
        // address properties here
    }
} 

В противном случае вам нужно обновить ваш объект C #, чтобы он соответствовал JSON, что будет означать индивидуальные свойства для каждого элемента в JSON:

public class Customer
{
    public long Id { get; set; }

    public string UserName { get; set; }

    public string Address { get; set; }

    public string Address2 { get; set; }

    public string City { get; set; }

    public string State { get; set; }

    public string ZIP { get; set; }
}

Кроме того, если вы настраиваете оба из них,название улицы, вероятно, не должно называться «адрес».Для меня слово «адрес» означает название улицы, номер, город, штат и ZIP как одно целое.

Если у вас нет контроля над JSON, то нет никакого реального способа чистодесериализовать JSON в ваш объект с помощью чего-то вроде Json.Net.Вам нужно будет установить какой-то тип сопоставления или искать свойства напрямую, чтобы получить их значения, чтобы добавить их в ваш объект.Вы можете проанализировать JSON в объект JObject, а затем получить доступ к нужным вам свойствам.

JObject foo = JObject.Parse(//your JSON string here);
customer.Address = (string)foo["Address"];
customer.Address2 = (string)foo["Address2];

В общем, если вы не контролируете структуру JSON, вероятно, лучше всего просто сделать ваши объектысоответствует JSON, который вы дали.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...