2010-03-30 18 views
123

Sono relativamente nuovo a lavorare con i dati C# e JSON e sto cercando indicazioni. Sto usando C# 3.0, con .NET3.5SP1 e JSON.NET 3.5r6.Deserializzazione dei dati JSON in C# utilizzando JSON.NET

Ho una classe C# definita che ho bisogno di compilare da una struttura JSON. Tuttavia, non tutte le strutture JSON per una voce recuperate dal servizio Web contengono tutti gli attributi possibili definiti nella classe C#.

Sto facendo quello che sembra essere il modo sbagliato, difficile e basta individuare ogni valore uno per uno dal JObject e trasformare la stringa nella proprietà di classe desiderata.

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

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

Qual è il modo migliore per deserializzare una struttura JSON nella classe C# di spedizione possibili dati mancanti dalla fonte JSON?

La mia classe è definita come:

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

    } 

E un campione del JSON da analizzare è:

{ 
    "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" 
    ] 
} 

risposta

70

Hai provato a usare il metodo DeserializeObject generica?

JsonConvert.DeserializeObject<MyAccount>(myjsondata); 

Qualsiasi campo mancante nei dati JSON deve essere semplicemente lasciato NULL.

UPDATE:

Se la stringa JSON è un array, provate questo:

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

jarray dovrebbe quindi essere un List<MyAccount>.

un altro aggiornamento:

L'eccezione che stai ricevendo non è coerente con una serie di oggetti- penso che il serializzatore sta avendo problemi con il accountstatusmodifiedby proprietà Dizionario tipizzato.

Provare ad escludere la serializzazione accountstatusmodifiedby dalla serializzazione e vedere se questo aiuta. Se lo fa, potresti dover rappresentare questa proprietà in modo diverso.

Documentazione: Serializing and Deserializing JSON with Json.NET

+0

Grazie. Tuttavia, viene visualizzato l'errore "Impossibile deserializzare l'array JSON in tipo" System.String "." quando tenta di deserializzare (ad esempio) l'array givenname JSON nella stringa GivenName della classe. Gli attributi JSON che ho definito come stringa nella classe C# sono sempre solo array di elementi singoli. Questo è il motivo per cui ho iniziato a scegliere i valori uno per uno mentre mi sono imbattuto in questo tipo di problema durante il processo di deserializzazione. L'altra magia che sto trascurando? –

+0

risposta aggiornato ... –

+0

Quindi ... 'DateTime AccountStatusExpiration' (per esempio) non è annullabile come definito nel codice. Cosa ci vorrebbe per renderlo nullable? Basta cambiare 'DateTime' a' DateTime? '? –

8

è possibile utilizzare:

JsonConvert.PopulateObject(json, obj); 

qui: json è la stringa JSON, obj è l'oggetto di destinazione.Vedi: example

Nota: PopulateObject() volontà non cancellerà di obj dati della lista, dopo Populate(), obj's membro della lista volontà contiene i suoi dati ei dati originali da stringa JSON

+2

PopulateObject - Populate non è nel modello a oggetti. – amok

+0

Non funziona in oggetti C# complessi. – SutharMonil

+1

Questo ha funzionato PERFETTO per me! Stavo avendo problemi dove ho avuto una stringa JSON piuttosto complessa, quando ho cercato di gettarlo ai oggetti C#, qualsiasi cosa contrassegnati come 'NotNull' sarebbe manca l'oggetto, anche se era presente nella stringa JSON per cominciare. Molto strano. Ho usato questo metodo e ha funzionato PERFETTO! – jward01

256

Usa JsonConvert.DeserializeObject<RootObject>(string json);

Crea il tuo lezioni su JSON 2 C#


Documentazione Json.NET: Serializing and Deserializing JSON with Json.NET

+27

In Visual Studio è inoltre disponibile l'opzione Incolla JSON come classi nel menu Modifica-Incolla speciale. –

0

Supponendo che i dati del campione siano corretti, il tuo givenname e le altre voci racchiuse tra parentesi sono array in JS ... ti consigliamo di utilizzare Elenco per questi tipi di dati. ed Elenco per dire accountstatusexpmaxdate ... Penso che per esempio le date siano state formattate in modo errato, quindi incerto su cosa altro non è corretto nell'esempio.

Questo è un vecchio post, ma ha voluto prendere nota dei problemi.

1

Si può provare a controllare alcuni generatori di classi online per ulteriori informazioni. Tuttavia, credo che alcune delle risposte siano state utili. Ecco il mio approccio che potrebbe essere utile.

Il seguente codice è stato creato con un metodo dinamico in 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"]); 

      } 
     } 

Questo codice permette in sostanza di accedere ai membri contenuti nella stringa JSON. Solo in un modo diverso senza bisogno delle classi. query, trend e url sono gli oggetti contenuti nella stringa Json.

È inoltre possibile utilizzare this website. Non fidarti delle classi al 100% ma ottieni l'idea.

45

risposta riprodotta da https://stackoverflow.com/a/10718128/776476

È possibile utilizzare il tipo C# dynamic per rendere le cose più facili. Questa tecnica rende anche il ri-factoring più semplice in quanto non si basa su stringhe magiche.

JSON

La stringa json segue è una risposta semplice da una chiamata http api e definisce due proprietà: Id e Name.

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

C#

Usa JsonConvert.DeserializeObject<dynamic>() deserializzare questa stringa in un tipo dinamico quindi è sufficiente accedere alla sua proprietà nel solito modo.

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

Nota: Il collegamento NuGet per l'assemblaggio NewtonSoft è http://nuget.org/packages/newtonsoft.json. Non dimenticare di aggiungere: using Newtonsoft.Json; per accedere a tali classi.

+5

Adoro l'uso di . Tuttavia, ho dovuto fare questo per farlo funzionare:.. Tradurrà [ "Id"] Valore e causare [ "Nome"] Valore – fredw

+0

Sebbene dinamica è una bella alternativa, gli esempi di cui sopra non utilizzano 'archi magici', ma sono invece utilizzando generici fortemente tipizzati che vengono aggiornati durante le normali tecniche di refactoring VS (a meno che non si trovi all'interno di una vista in MVC che non rientra nell'ambito di questa domanda). – gcoleman0828

+1

Hai ancora "stringhe magiche", ora sono semplicemente nascoste dall'uso della dinamica! –

3

Compilando la risposta di bbant, questa è la mia soluzione completa per deserializzare JSON da un URL remoto.

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 sarebbe come:

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

Dove FeedResult è la classe generata utilizzando il Xamasoft JSON Class Generator

Ecco uno screenshot delle impostazioni che ho usato, consentendo di nomi di proprietà strani che la web version non poteva giustificare.

Xamasoft JSON Class Generator

1

ho trovato il mio avevo costruito il mio oggetto in modo non corretto. Ho usato http://json2csharp.com/ per generare la mia classe oggetto da JSON. Una volta ottenuto il corretto Oject, sono riuscito a eseguire il cast senza problemi. Norbit, errore di Noob. Ho pensato di aggiungerlo nel caso avessi lo stesso problema.

Problemi correlati