2012-06-20 270 views
41

Aquí está mi clase simple User POCO:JsonConvert.DeserializeObject deserializar JSON para una clase C# POCO

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

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

    /// <summary> 
    /// A User's 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's linked accounts. 
    /// </summary> 
    public List<Account> Accounts { get; set; } 

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

} 

Y el método que estoy usando para deserializar una respuesta JSON en un objeto User (este real JSON call is here):

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

Esto dispara una excepción:

No se puede deserializar el objeto JSON actual (p. {"name": "value"}) en el tipo 'System.Collections.Generic.List`1 [CoderwallDotNet.Api.Models.Account]' porque el tipo requiere una matriz JSON (por ejemplo, [1,2,3] ]) para deserializar correctamente.

Para corregir este error ya sea cambiar el JSON a una matriz JSON (por ejemplo, [1,2,3]) o cambiar el tipo deserializado de modo que es una normal de tipo de .NET (por ejemplo, no un tipo primitivo como número entero , no una colección escriba como una matriz o Lista) que se puede deserializar desde un objeto JSON . JsonObjectAttribute también se puede agregar al tipo para forzarlo a para deserializar desde un objeto JSON. Path 'accounts.github', la línea 1, posición 129.

Como nunca había trabajado con este método DeserializeObject antes, estoy un poco atascado aquí.

Me he asegurado de que los nombres de las propiedades en la clase POCO sean los mismos que los nombres en la respuesta JSON.

¿Qué puedo intentar deserializar a JSON en esta clase de POCO?

+0

Parece que llego tarde, pero veo mi respuesta. usar 'JsonProperty' es mucho más fácil (y legible) que escribir' JsonConverter' –

+0

Probablemente estés viendo algo así entonces. http://stackoverflow.com/questions/25672338/dynamically-deserialize-json-into-any-object-passed-in-c-sharp – Jim

Respuesta

69

Aquí hay un ejemplo de trabajo.

Keypoints son:

  • Declaración de Accounts
  • El uso de JsonProperty atributo

.

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's username. eg: "sergiotapia, mrkibbles, matumbo" 
    /// </summary> 
    [JsonProperty("username")] 
    public string Username { get; set; } 

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

    /// <summary> 
    /// A User's 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's linked accounts. 
    /// </summary> 
    [JsonProperty("accounts")] 
    public Account Accounts { get; set; } 

    /// <summary> 
    /// A collection of the User's 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; 
} 
+0

Eso dio como resultado un código mucho más limpio. Ya había implementado un Serializador personalizado, pero me gusta más este enfoque ya que es más simple. ¡Gracias de nuevo! –

+8

¿Olvidó la Lista <> en Cuenta, o me falta algo? Me parece que la pregunta original tenía Cuentas como una lista, pero esta solución tiene Cuentas como un único objeto de Cuenta ... no una matriz, ni una lista. – huntharo

+2

@huntharo Parece que la declaración 'Cuentas 'modificada - de' Lista 'a' Cuenta' - se debe a que el JSON de ejemplo (vinculado en la pregunta) tiene un objeto JSON individual, no una matriz, para 'cuentas ':' "cuentas": {"github": "sergiotapia"} ' –

2

La propiedad cuentas se define así:

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

Sus estados Poco Esta:

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

Trate de usar este JSON:

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

Una serie de artículos (que es va a mapearse a la lista) siempre se incluye entre corchetes.

Editar: La Cuenta Poco será algo como esto:

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

y tal vez otras propiedades.

Edición 2: Para no tiene una matriz utilizar la propiedad de la siguiente manera:

public Account Accounts { get; set; } 

con algo así como la clase de ejemplo que he publicado en la primera edición.

+0

Simplemente defina la propiedad no como una lista.Estoy editando mi respuesta (Edit2) – Sascha

2
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.` 

El mensaje completo indica que es posible serializar a un objeto List, pero la entrada debe ser una lista JSON. Esto significa que su JSON debe contener

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

Cuando los datos AccountObject es JSON representa a su objeto de cuenta o su objeto Placa

Lo que parece estar actualmente es

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

donde las cuentas se un objeto JSON (indicado por llaves), no una matriz de objetos JSON (las matrices se indican con corchetes), que es lo que desea. Pruebe

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

El JSON real está en la pregunta. –

+0

Vaya, editando ahora edite: Listo. Perdón por no haber notado eso; el descremado no siempre es óptimo; P –

4

Puede crear un JsonConverter. Vea here para un ejemplo que es similar a su pregunta.

+0

** Exactamente ** lo que esperaba que existiera. Definitivamente voy a echar un vistazo a esto. ¡Gracias! –

+0

No hay problema, me alegro de poder ayudar. – SwDevMan81

4

Otro, y más racional, el enfoque de deserializar una cadena JSON camello entubado a un objeto POCO-Pascal entubado es utilizar el CamelCasePropertyNamesContractResolver.

Es parte del espacio de nombres de Newtonsoft.Json.Serialization. Este enfoque supone que la única diferencia entre el objeto JSON y el POCO reside en la carcasa de los nombres de las propiedades. Si los nombres de las propiedades se deletrean de manera diferente, entonces deberá recurrir al uso de los atributos de JsonProperty para mapear los nombres de las propiedades.

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

Eso no es exactamente lo que tenía en mente. ¿Qué haces si tienes un tipo genérico para que solo se conozca en tiempo de ejecución?

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); 
    } 
} 
Cuestiones relacionadas