2012-02-26 34 views
9

Estoy tratando de deserializar una información json en una clase de modelo, pero estoy fallando. Aquí es lo que hago:No se puede deserializar la matriz JSON en tipo - Json.NET

public CountryModel GetCountries() { 

     using (WebClient client = new WebClient()) { 

      var result = client.DownloadString("http://api.worldbank.org/incomeLevels/LIC/countries?format=json"); 

      var output = JsonConvert.DeserializeObject<List<CountryModel>>(result); 

      return output.First(); 
     } 
    } 

Así es como mi modelo se parece a:

public class CountryModel 
{ 
    public int Page { get; set; } 
    public int Pages { get; set; } 
    public int Per_Page { get; set; } 
    public int Total { get; set; } 

    public List<Country> Countries { get; set; } 
} 

public class Country 
{ 
    public int Id { get; set; } 
    public string Iso2Code { get; set; } 
    public string Name { get; set; } 
    public Region Region { get; set; } 
} 

public class Region 
{ 
    public int Id { get; set; } 
    public string Value { get; set; } 
} 

Se puede ver el JSON que estoy recibiendo aquí: http://api.worldbank.org/incomeLevels/LIC/countries?format=json

Este es el error que consigo:

No se puede deserializar la matriz JSON en el tipo 'Mvc4AsyncSample.Models.CountryModel'. Línea 1, posición 1.

+2

que no parece como una buena representación JSON. Tal vez sería mejor si utilizó el formato XML. – svick

+0

Sí, eso creo. Ponen un solo objeto dentro de una matriz. No debería estar allí, creo. Cualquier forma posible de moverse? – tugberk

+0

El XML es mucho más limpio, yo iría por eso: http://api.worldbank.org/incomeLevels/LIC/countries?format=xml –

Respuesta

17

Tienes que escribir una costumbre JsonConverter:

public class CountryModelConverter : JsonConverter 
    { 

     public override bool CanConvert(Type objectType) 
     { 
      if (objectType == typeof(CountryModel)) 
      { 
       return true; 
      } 

      return false; 
     } 

     public override object ReadJson(JsonReader reader, Type objectType 
      , object existingValue, JsonSerializer serializer) 
     { 
      reader.Read(); //start array 
      //reader.Read(); //start object 
      JObject obj = (JObject)serializer.Deserialize(reader); 

      //{"page":1,"pages":1,"per_page":"50","total":35} 
      var model = new CountryModel(); 

      model.Page = Convert.ToInt32(((JValue)obj["page"]).Value); 
      model.Pages = Convert.ToInt32(((JValue)obj["pages"]).Value); 
      model.Per_Page = Int32.Parse((string) ((JValue)obj["per_page"]).Value); 
      model.Total = Convert.ToInt32(((JValue)obj["total"]).Value); 

      reader.Read(); //end object 

      model.Countries = serializer.Deserialize<List<Country>>(reader); 

      reader.Read(); //end array 

      return model; 
     } 

     public override void WriteJson(JsonWriter writer, object value 
      , JsonSerializer serializer) 
     { 
      throw new NotImplementedException(); 
     } 
    } 

y la etiqueta de la CountryModel con ese convertidor (también tuvo que cambiar algunos int a string):

[JsonConverter(typeof(CountryModelConverter))] 
    public class CountryModel 
    { 
     public int Page { get; set; } 
     public int Pages { get; set; } 
     public int Per_Page { get; set; } 
     public int Total { get; set; } 

     public List<Country> Countries { get; set; } 
    } 

    public class Country 
    { 
     public string Id { get; set; } 
     public string Iso2Code { get; set; } 
     public string Name { get; set; } 
     public Region Region { get; set; } 
    } 

    public class Region 
    { 
     public string Id { get; set; } 
     public string Value { get; set; } 
    } 

Entonces usted debería poder deserializar así:

var output = JsonConvert.DeserializeObject<CountryModel>(result); 
+0

¿No puede simplificar la deserialización de las propiedades de 'CountryModel' utilizando' serializer.Deserialize (reader) '? – svick

+0

La respuesta de svick es mejor si solo necesitas leer, el 'JsonConverter' solo es realmente necesario si tienes que ir en ambas direcciones. –

+2

@svick Pensé en eso, el problema es que 'CountryModel' tiene el atributo, por lo que entra en un bucle infinito, se simplificaría si el modelo de objeto cambiara, pero yo estaba tratando de mantener su modelo de objetos. –

12

Parece un intento (no muy bueno) de representar XML en JSON. El JSON se ve así:

[ 
    { 
    "page": 1, 
    … 
    }, 
    [ 
    { 
     "id": "AFG", 
     "name": "Afghanistan", 
     … 
    }, 
    { 
     "id": "BDI", 
     "name": "Burundi", 
     … 
    }, 
    … 
    ] 
] 

Mientras que un JSON razonable (que sería asignar dicho sea de paso a su modelo muy bien) se vería así:

{ 
    "page": 1, 
    …, 
    "countries": [ 
    { 
     "id": "AFG", 
     "name": "Afghanistan", 
     … 
    }, 
    { 
     "id": "BDI", 
     "name": "Burundi", 
     … 
    }, 
    … 
    ] 
} 

Si está seguro de que desea utilizar JSON (y no XML), puede hacerlo por primera deserializar el JSON en modelo de objetos de JSON.NET y luego deserializar que en su modelo:

var json = client.DownloadString("http://api.worldbank.org/incomeLevels/LIC/countries?format=json"); 

var array = (JArray)JsonConvert.DeserializeObject(json); 

var serializer = new JsonSerializer(); 

var countryModel = serializer.Deserialize<CountryModel>(array[0].CreateReader()); 

countryModel.Countries = serializer.Deserialize<List<Country>>(array[1].CreateReader()); 

return countryModel; 

no se olvide de cambiar sus propiedades a Idstring, porque eso es lo que son.

+0

Mucho más simple que mi versión, lindo, no sabía que podía crear el lector fuera de los objetos incorporados. –

-1

Su modelo no coincide con la estructura JSON. Parece que te faltan las últimas 6 propiedades.

{ 
"id": "AFG", 
"iso2Code": "AF", 
"name": "Afghanistan", 
"region": { 
    "id": "SAS", 
    "value": "South Asia" 
}, 
"adminregion": { 
    "id": "SAS", 
    "value": "South Asia" 
}, 
"incomeLevel": { 
    "id": "LIC", 
    "value": "Low income" 
}, 
"lendingType": { 
    "id": "IDX", 
    "value": "IDA" 
}, 
"capitalCity": "Kabul", 
"longitude": "69.1761", 
"latitude": "34.5228" 

}

+7

esto no afecta el proceso de deserialización. – tugberk

Cuestiones relacionadas