2010-03-30 25 views
123

Soy relativamente nuevo en el trabajo con datos C# y JSON y busco orientación. Estoy usando C# 3.0, con .NET3.5SP1 y JSON.NET 3.5r6.Deserialización de datos JSON a C# usando JSON.NET

Tengo una clase C# definida que necesito completar de una estructura JSON. Sin embargo, no todas las estructuras JSON para una entrada que se recupera del servicio web contienen todos los atributos posibles que se definen dentro de la clase C#.

He estado haciendo lo que parece ser el camino equivocado, difícil y simplemente seleccionando cada valor uno por uno desde JObject y transformando la cadena en la propiedad de clase deseada.

JsonSerializer serializer = new JsonSerializer(); 
var o = (JObject)serializer.Deserialize(myjsondata); 

MyAccount.EmployeeID = (string)o["employeeid"][0]; 

¿Cuál es la mejor manera de deserializar una estructura JSON en la clase C# y gastos de posible falta de datos de la fuente JSON?

Mi clase se define como:

public class MyAccount 
    { 

    [JsonProperty(PropertyName = "username")] 
    public string UserID { get; set; } 

    [JsonProperty(PropertyName = "givenname")] 
    public string GivenName { get; set; } 

    [JsonProperty(PropertyName = "sn")] 
    public string Surname { get; set; } 

    [JsonProperty(PropertyName = "passwordexpired")] 
    public DateTime PasswordExpire { get; set; } 

    [JsonProperty(PropertyName = "primaryaffiliation")] 
    public string PrimaryAffiliation { get; set; } 

    [JsonProperty(PropertyName = "affiliation")] 
    public string[] Affiliation { get; set; } 

    [JsonProperty(PropertyName = "affiliationstatus")] 
    public string AffiliationStatus { get; set; } 

    [JsonProperty(PropertyName = "affiliationmodifytimestamp")] 
    public DateTime AffiliationLastModified { get; set; } 

    [JsonProperty(PropertyName = "employeeid")] 
    public string EmployeeID { get; set; } 

    [JsonProperty(PropertyName = "accountstatus")] 
    public string AccountStatus { get; set; } 

    [JsonProperty(PropertyName = "accountstatusexpiration")] 
    public DateTime AccountStatusExpiration { get; set; } 

    [JsonProperty(PropertyName = "accountstatusexpmaxdate")] 
    public DateTime AccountStatusExpirationMaxDate { get; set; } 

    [JsonProperty(PropertyName = "accountstatusmodifytimestamp")] 
    public DateTime AccountStatusModified { get; set; } 

    [JsonProperty(PropertyName = "accountstatusexpnotice")] 
    public string AccountStatusExpNotice { get; set; } 

    [JsonProperty(PropertyName = "accountstatusmodifiedby")] 
    public Dictionary<DateTime, string> AccountStatusModifiedBy { get; set; } 

    [JsonProperty(PropertyName = "entrycreatedate")] 
    public DateTime EntryCreatedate { get; set; } 

    [JsonProperty(PropertyName = "entrydeactivationdate")] 
    public DateTime EntryDeactivationDate { get; set; } 

    } 

y una muestra de la JSON para analizar es:

{ 
    "givenname": [ 
     "Robert" 
    ], 
    "passwordexpired": "20091031041550Z", 
    "accountstatus": [ 
     "active" 
    ], 
    "accountstatusexpiration": [ 
     "20100612000000Z" 
    ], 
    "accountstatusexpmaxdate": [ 
     "20110410000000Z" 
    ], 
    "accountstatusmodifiedby": { 
     "20100214173242Z": "tdecker", 
     "20100304003242Z": "jsmith", 
     "20100324103242Z": "jsmith", 
     "20100325000005Z": "rjones", 
     "20100326210634Z": "jsmith", 
     "20100326211130Z": "jsmith" 
    }, 
    "accountstatusmodifytimestamp": [ 
     "20100312001213Z" 
    ], 
    "affiliation": [ 
     "Employee", 
     "Contractor", 
     "Staff" 
    ], 
    "affiliationmodifytimestamp": [ 
     "20100312001213Z" 
    ], 
    "affiliationstatus": [ 
     "detached" 
    ], 
    "entrycreatedate": [ 
     "20000922072747Z" 
    ], 
    "username": [ 
     "rjohnson" 
    ], 
    "primaryaffiliation": [ 
     "Staff" 
    ], 
    "employeeid": [ 
     "999777666" 
    ], 
    "sn": [ 
     "Johnson" 
    ] 
} 

Respuesta

70

¿Ha intentado utilizar el método DeserializeObject genérico?

JsonConvert.DeserializeObject<MyAccount>(myjsondata); 

Cualquier campo faltante en los datos JSON simplemente debe dejarse NULO.

ACTUALIZACIÓN:

Si la cadena JSON es una matriz, intente esto:

var jarray = JsonConvert.DeserializeObject<List<MyAccount>>(myjsondata); 

jarray continuación, debería ser un List<MyAccount>.

Otra actualización:

La excepción que está recibiendo no es compatible con una gran variedad de objetos- Creo que el serializador está teniendo problemas con su diccionario-mecanografiado accountstatusmodifiedby propiedad.

Pruebe excluyendo la propiedad accountstatusmodifiedby de la serialización y vea si eso ayuda. Si lo hace, es posible que deba representar esa propiedad de manera diferente.

Documentación: Serializing and Deserializing JSON with Json.NET

+0

Gracias. Sin embargo, aparece un error de "No se puede deserializar la matriz JSON en el tipo 'System.String'". cuando está tratando de deserializar (por ejemplo) el conjunto de nombres dados JSON en la clase cadena GivenName. Los atributos JSON que he definido como cadena en la clase C# son solo matrices de un solo elemento. Esta es la razón por la que comencé a elegir los valores uno por uno cuando me encontré con este tipo de problema durante el proceso de deserialización. Otra magia que estoy pasando por alto? –

+0

respuesta actualizada ... –

+0

Entonces ... 'DateTime AccountStatusExpiration' (por ejemplo) no puede contener nulos como se define en el código. ¿Qué se necesitaría para que sea nulo? Simplemente cambie 'DateTime' a' DateTime? '? –

8

que puede utilizar:

JsonConvert.PopulateObject(json, obj); 

aquí: json es la cadena JSON, obj es el objeto de destino.Ver: example

Nota: PopulateObject() voluntad no borrar datos de la lista obj de, después de Populate(), obj's voluntad miembro de la lista contiene sus datos y los datos originales de la cadena JSON

+2

es PopulateObject - Populate no está en el modelo de objetos. – amok

+0

No funciona en objetos C# complejos. – SutharMonil

+1

¡Esto funcionó PERFECTO para mí! Estaba teniendo problemas donde tenía una cadena JSON bastante compleja, cuando intenté convertirla en objetos C#, cualquier cosa marcada como 'NotNull' faltaría en el objeto, aunque estaba presente en la cadena JSON para empezar. Muy extraño. ¡Utilicé este método y funcionó PERFECTAMENTE! – jward01

0

Suponiendo que sus datos de muestra son correctos, su nombre de pila y otras entradas entre corchetes son matrices en JS ... querrá usar List para esos tipos de datos. y List for say accountstatusexpmaxdate ... Creo que su ejemplo tiene las fechas incorrectamente formateadas, por lo que no está seguro de qué más es incorrecto en su ejemplo.

Esta es una publicación anterior, pero quería tomar nota de los problemas.

1

Puede intentar consultar algunos de los generadores de clase en línea para obtener más información. Sin embargo, creo que algunas de las respuestas han sido útiles. Aquí está mi enfoque que puede ser útil.

El siguiente código se realizó con un método dinámico en mente.

dynObj = (JArray)JsonConvert.DeserializeObject(nvm); 

     foreach (JObject item in dynObj) 
     { 
      foreach (JObject trend in item["trends"]) 
      { 
     Console.WriteLine("{0}-{1}-{2}", trend["query"], trend["name"], trend["url"]); 

      } 
     } 

Este código básicamente le permite acceder a los miembros contenidos en la cadena Json. Solo de una manera diferente sin la necesidad de las clases. query, trend y url son los objetos contenidos en la cadena Json.

También puede usar this website. No confíes en las clases al 100% pero entiendes la idea.

45

respuesta reproducida de https://stackoverflow.com/a/10718128/776476

Usted puede utilizar el tipo C# dynamic para facilitar las cosas. Esta técnica también simplifica el refaccionamiento, ya que no depende de cadenas mágicas.

Json

La cadena json a continuación es una respuesta sencilla a partir de una llamada http api y define dos propiedades: Id y Name.

{"Id": 1, "Name": "biofractal"} 

C#

Uso JsonConvert.DeserializeObject<dynamic>() deserializar esta cadena en un tipo dinámico entonces simplemente acceder a sus propiedades de la forma habitual.

var results = JsonConvert.DeserializeObject<dynamic>(json); 
var id = results.Id; 
var name= results.Name; 

Nota: El enlace NuGet para el montaje NewtonSoft es http://nuget.org/packages/newtonsoft.json. No olvide agregar: using Newtonsoft.Json; para acceder a esas clases.

+5

Me encanta el uso de . Sin embargo, tuve que hacer esto para que funcione: resultado ["Id"]. Valor y resultado ["Nombre"]. Valor – fredw

+0

Aunque la dinámica es una buena alternativa, los ejemplos anteriores no usan 'cadenas mágicas', sino que son utilizando genéricos fuertemente tipados que se actualizan durante las técnicas normales de refactorización VS (a menos que estén dentro de una Vista en MVC que está fuera del alcance de esta pregunta). – gcoleman0828

+1

¡Todavía tiene 'cadenas mágicas', ahora están simplemente ocultas por el uso de la dinámica! –

3

Basado en la respuesta de bbant, esta es mi solución completa para deserializar JSON desde una URL remota.

using Newtonsoft.Json; 
using System.Net.Http; 

namespace Base 
{ 
    public class ApiConsumer<T> 
    { 
     public T data; 
     private string url; 

     public CalendarApiConsumer(string url) 
     { 
      this.url = url; 
      this.data = getItems(); 
     } 

     private T getItems() 
     { 
      T result = default(T); 
      HttpClient client = new HttpClient(); 

      // This allows for debugging possible JSON issues 
      var settings = new JsonSerializerSettings 
      { 
       Error = (sender, args) => 
       { 
        if (System.Diagnostics.Debugger.IsAttached) 
        { 
         System.Diagnostics.Debugger.Break(); 
        } 
       } 
      }; 

      using (HttpResponseMessage response = client.GetAsync(this.url).Result) 
      { 
       if (response.IsSuccessStatusCode) 
       { 
        result = JsonConvert.DeserializeObject<T>(response.Content.ReadAsStringAsync().Result, settings); 
       } 
      } 
      return result; 
     } 
    } 
} 

uso sería como:

ApiConsumer<FeedResult> feed = new ApiConsumer<FeedResult>("http://example.info/feeds/feeds.aspx?alt=json-in-script"); 

Dónde FeedResult es la clase generada mediante el Xamasoft JSON Class Generator

Aquí está una captura de pantalla de los ajustes que utilicé, teniendo en cuenta los nombres de propiedades extrañas, que la web version no podría explicar.

Xamasoft JSON Class Generator

1

me encontré a mi me había construido mi objeto incorrectamente. Usé http://json2csharp.com/ para generar mi clase de objeto desde JSON. Una vez que tuve el objeto correcto, pude lanzar sin problemas. Norbit, error novato. Pensé que lo agregaría en caso de que tenga el mismo problema.

Cuestiones relacionadas