Использование JsonConvert.DeserializeObject для десериализации Json в класс С# POCO

Вот мой простой класс User POCO:

/// <summary>
/// The User class represents a Coderwall User.
/// </summary>
public class User
{
    /// <summary>
    /// A User username. eg: "sergiotapia, mrkibbles, matumbo"
    /// </summary>
    public string Username { get; set; }

    /// <summary>
    /// A User name. eg: "Sergio Tapia, John Cosack, Lucy McMillan"
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// A User location. eh: "Bolivia, USA, France, Italy"
    /// </summary>
    public string Location { get; set; }

    public int Endorsements { get; set; } //Todo.
    public string Team { get; set; } //Todo.

    /// <summary>
    /// A collection of the User linked accounts.
    /// </summary>
    public List<Account> Accounts { get; set; }

    /// <summary>
    /// A collection of the User awarded badges.
    /// </summary>
    public List<Badge> Badges { get; set; }

}

И метод, который я использую для десериализации ответа JSON в объект User (этот фактический JSON-вызов здесь):

private User LoadUserFromJson(string response)
{
    var outObject = JsonConvert.DeserializeObject<User>(response);
    return outObject;
}

Это вызывает исключение:

Невозможно десериализовать текущий объект JSON (например, { "name": "value" }) в тип 'System.Collections.Generic.List`1 [CoderwallDotNet.Api.Models.Account] потому что для этого требуется массив JSON (например, [1,2,3]) для десериализации правильно.

Чтобы исправить эту ошибку, либо измените JSON на массив JSON (например, [1,2,3]) или изменить десериализованный тип, чтобы он был нормальным Тип .NET(например, не примитивный тип типа integer, а не набор тип, подобный массиву или списку), который можно десериализовать из JSON объект. JsonObjectAttribute также можно добавить к типу, чтобы заставить его для десериализации из объекта JSON. Путь "accounts.github", строка 1, позиция 129.

Никогда ранее не работал с этим методом DeserializeObject, я как бы застрял здесь.

Я убедился, что имена свойств в классе POCO совпадают с именами в ответе JSON.

Что я могу попробовать десериализовать JSON в этом классе POCO?

Ответ 1

Вот рабочий пример.

Ключевые точки:

  • Объявление Accounts
  • Использование атрибута JsonProperty

.

using (WebClient wc = new WebClient())
{
    var json = wc.DownloadString("http://coderwall.com/mdeiters.json");
    var user = JsonConvert.DeserializeObject<User>(json);
}

-

public class User
{
    /// <summary>
    /// A User username. eg: "sergiotapia, mrkibbles, matumbo"
    /// </summary>
    [JsonProperty("username")]
    public string Username { get; set; }

    /// <summary>
    /// A User name. eg: "Sergio Tapia, John Cosack, Lucy McMillan"
    /// </summary>
    [JsonProperty("name")]
    public string Name { get; set; }

    /// <summary>
    /// A User location. eh: "Bolivia, USA, France, Italy"
    /// </summary>
    [JsonProperty("location")]
    public string Location { get; set; }

    [JsonProperty("endorsements")]
    public int Endorsements { get; set; } //Todo.

    [JsonProperty("team")]
    public string Team { get; set; } //Todo.

    /// <summary>
    /// A collection of the User linked accounts.
    /// </summary>
    [JsonProperty("accounts")]
    public Account Accounts { get; set; }

    /// <summary>
    /// A collection of the User awarded badges.
    /// </summary>
    [JsonProperty("badges")]
    public List<Badge> Badges { get; set; }
}

public class Account
{
    public string github;
}

public class Badge
{
    [JsonProperty("name")]
    public string Name;
    [JsonProperty("description")]
    public string Description;
    [JsonProperty("created")]
    public string Created;
    [JsonProperty("badge")]
    public string BadgeUrl;
}

Ответ 2

Вы можете создать JsonConverter. См. здесь для примера, аналогичного вашему вопросу.

Ответ 3

Другим и более упорядоченным подходом к десериализации строки JSON с верблюжьей оболочкой в ​​объект POCO с паскальным обложением является использование CamelCasePropertyNamesContractResolver.

Это часть пространства имен Newtonsoft.Json.Serialization. Этот подход предполагает, что единственная разница между объектом JSON и POCO заключается в оболочке имен свойств. Если имена свойств пишутся по-разному, вам нужно прибегнуть к использованию атрибутов JsonProperty для отображения имен свойств.

using Newtonsoft.Json; 
using Newtonsoft.Json.Serialization;

. . .

private User LoadUserFromJson(string response) 
{
    JsonSerializerSettings serSettings = new JsonSerializerSettings();
    serSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    User outObject = JsonConvert.DeserializeObject<User>(jsonValue, serSettings);

    return outObject; 
}

Ответ 4

Свойство учетных записей определяется следующим образом:

"accounts":{"github":"sergiotapia"}

В POCO указано следующее:

public List<Account> Accounts { get; set; }

Попробуйте использовать этот Json:

"accounts":[{"github":"sergiotapia"}]

Массив элементов (который будет отображаться в списке) всегда заключен в квадратные скобки.

Изменить: Учетная запись Poco будет выглядеть примерно так:

class Account {
    public string github { get; set; }
}

и, возможно, другие свойства.

Изменить 2: Чтобы не иметь массив, используйте свойство следующим образом:

public Account Accounts { get; set; }

с чем-то вроде класса образца, который я опубликовал в первом редактировании.

Ответ 5

to fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the
deserialized type so that it is a normal .NET type (e.g. not a primitive type like
integer, not a collection type like an array or List) that can be deserialized from a
JSON object.`

Все сообщение указывает, что можно сериализовать объект List, но вход должен быть списком JSON. Это означает, что ваш JSON должен содержать

"accounts" : [{<AccountObjectData}, {<AccountObjectData>}...],

Где данные AccountObject - это JSON, представляющий объект вашей учетной записи или объект значка

В настоящее время он выглядит как

"accounts":{"github":"sergiotapia"}

Если учетными записями является объект JSON (обозначается фигурной скобкой), а не массив объектов JSON (массивы обозначаются скобками), это то, что вы хотите. Попробуйте

"accounts" : [{"github":"sergiotapia"}]

Ответ 6

Это не совсем то, что я имел в виду. Что вы делаете, если у вас есть общий тип, который будет известен только во время выполнения?

public MyDTO toObject() {
  try {
    var methodInfo = MethodBase.GetCurrentMethod();
    if (methodInfo.DeclaringType != null) {
      var fullName = methodInfo.DeclaringType.FullName + "." + this.dtoName;
      Type type = Type.GetType(fullName);
      if (type != null) {
        var obj = JsonConvert.DeserializeObject(payload);
      //var obj = JsonConvert.DeserializeObject<type.MemberType.GetType()>(payload);  // <--- type ?????
          ...
      }
    }

    // Example for java..   Convert this to C#
    return JSONUtil.fromJSON(payload, Class.forName(dtoName, false, getClass().getClassLoader()));
  } catch (Exception ex) {
    throw new ReflectInsightException(MethodBase.GetCurrentMethod().Name, ex);
  }
}

Ответ 7

В соответствии с принятым ответом, если у вас есть образец текста JSON, вы можете подключить его к этот конвертер, выберите свои параметры и сгенерировать код С#.

Если вы не знаете тип во время выполнения, этот вопрос выглядит так, как будто он подходит.

динамически десериализовать json в любой переданный объект. С#