Usando JsonConvert.DeserializeObject para desserializar o Json para uma class C # POCO

Aqui está minha class User POCO simples:

 ///  /// The User class represents a Coderwall User. ///  public class User { ///  /// A User's username. eg: "sergiotapia, mrkibbles, matumbo" ///  public string Username { get; set; } ///  /// A User's name. eg: "Sergio Tapia, John Cosack, Lucy McMillan" ///  public string Name { get; set; } ///  /// A User's location. eh: "Bolivia, USA, France, Italy" ///  public string Location { get; set; } public int Endorsements { get; set; } //Todo. public string Team { get; set; } //Todo. ///  /// A collection of the User's linked accounts. ///  public List Accounts { get; set; } ///  /// A collection of the User's awarded badges. ///  public List Badges { get; set; } } 

E o método que estou usando para desserializar uma resposta JSON em um object User (esta chamada JSON real está aqui ):

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

Isso triggers uma exceção:

Não é possível desserializar o object JSON atual (por exemplo, {“name”: “value”}) no tipo ‘System.Collections.Generic.List`1 [CoderwallDotNet.Api.Models.Account]’ porque o tipo requer um array JSON (por exemplo, [ 1,2,3]) para desserializar corretamente.

Para corrigir esse erro, altere o JSON para um array JSON (por exemplo, [1,2,3]) ou altere o tipo desserializado para que seja um tipo .NET normal (por exemplo, não um tipo primitivo como inteiro, não um tipo de coleção como uma matriz ou lista) que pode ser desserializada de um object JSON. JsonObjectAttribute também pode ser adicionado ao tipo para forçá-lo a desserializar de um object JSON. Caminho ‘accounts.github’, linha 1, posição 129.

Nunca tendo trabalhado com este método DeserializeObject antes, estou meio preso aqui.

Certifiquei-me de que os nomes das propriedades na class POCO são os mesmos que os da resposta JSON.

O que posso tentar desserializar JSON para esta class POCO?

Aqui está um exemplo de trabalho.

Pontos chave são:

  • Declaração de Accounts
  • Uso do atributo JsonProperty

.

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

 public class User { ///  /// A User's username. eg: "sergiotapia, mrkibbles, matumbo" ///  [JsonProperty("username")] public string Username { get; set; } ///  /// A User's name. eg: "Sergio Tapia, John Cosack, Lucy McMillan" ///  [JsonProperty("name")] public string Name { get; set; } ///  /// A User's location. eh: "Bolivia, USA, France, Italy" ///  [JsonProperty("location")] public string Location { get; set; } [JsonProperty("endorsements")] public int Endorsements { get; set; } //Todo. [JsonProperty("team")] public string Team { get; set; } //Todo. ///  /// A collection of the User's linked accounts. ///  [JsonProperty("accounts")] public Account Accounts { get; set; } ///  /// A collection of the User's awarded badges. ///  [JsonProperty("badges")] public List 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; } 

Você poderia criar um JsonConverter . Veja aqui um exemplo semelhante à sua pergunta.

Outra abordagem, mais simplificada, para desserializar uma cadeia JSON com casco de camelo para um object POCO com invólucro de pascal é usar o CamelCasePropertyNamesContractResolver .

Faz parte do namespace Newtonsoft.Json.Serialization. Essa abordagem assume que a única diferença entre o object JSON e o POCO reside no casing dos nomes das propriedades. Se os nomes das propriedades estiverem escritos de forma diferente, você precisará recorrer ao uso de atributos JsonProperty para mapear nomes de propriedades.

 using Newtonsoft.Json; using Newtonsoft.Json.Serialization; . . . private User LoadUserFromJson(string response) { JsonSerializerSettings serSettings = new JsonSerializerSettings(); serSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); User outObject = JsonConvert.DeserializeObject(jsonValue, serSettings); return outObject; } 

A propriedade de contas é definida assim:

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

Seu POCO afirma isso:

 public List Accounts { get; set; } 

Tente usar este Json:

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

Uma matriz de itens (que será mapeada para a lista) é sempre colocada entre colchetes.

Edit: A conta Poco será algo assim:

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

e talvez outras propriedades.

Editar 2: para não ter uma matriz, use a propriedade da seguinte maneira:

 public Account Accounts { get; set; } 

com algo parecido com a class de amostra que publiquei na primeira edição.

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

A mensagem inteira indica que é possível serializar para um object List, mas a input deve ser uma lista JSON. Isso significa que seu JSON deve conter

 "accounts" : [{}...], 

Onde os dados de AccountObject são JSON representando seu object Account ou seu object Badge

O que parece estar recebendo atualmente é

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

Onde as contas são um object JSON (denotado por chaves), não uma matriz de objects JSON (as matrizes são indicadas por colchetes), que é o que você deseja. Experimentar

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

Ao longo das linhas da resposta aceita, se você tiver uma amostra de texto JSON, você pode conectá-lo a este conversor , selecionar suas opções e gerar o código C #.

Se você não sabe o tipo em tempo de execução, este tópico parece que caberia.

dinamicamente desserializar json em qualquer object passado dentro c #

Isso não é exatamente o que eu tinha em mente. O que você faz se tiver um tipo genérico para ser conhecido apenas em tempo de execução?

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