2011-03-07 7 views
34

Estoy teniendo problemas para deserializar los datos devueltos por Facebook utilizando las bibliotecas JSON.NET.Deserialización de JSON cuando a veces la matriz y algunas veces el objeto

El JSON devueltos desde un simple publicación en el muro parece:

{ 
    "attachment":{"description":""}, 
    "permalink":"http://www.facebook.com/permalink.php?story_fbid=123456789" 
} 

El JSON devuelto una foto se ve así:

"attachment":{ 
     "media":[ 
      { 
       "href":"http://www.facebook.com/photo.php?fbid=12345", 
       "alt":"", 
       "type":"photo", 
       "src":"http://photos-b.ak.fbcdn.net/hphotos-ak-ash1/12345_s.jpg", 
       "photo":{"aid":"1234","pid":"1234","fbid":"1234","owner":"1234","index":"12","width":"720","height":"482"}} 
     ], 

Todo funciona muy bien y no tengo problemas. Ahora he encontrado con un simple publicación en el muro de un cliente móvil con el siguiente JSON, y deserialización ahora un error con este un solo mensaje:

"attachment": 
    { 
     "media":{}, 
     "name":"", 
     "caption":"", 
     "description":"", 
     "properties":{}, 
     "icon":"http://www.facebook.com/images/icons/mobile_app.gif", 
     "fb_object_type":"" 
    }, 
"permalink":"http://www.facebook.com/1234" 

Aquí es la clase que estoy deserializar como:

public class FacebookAttachment 
    { 
     public string Name { get; set; } 
     public string Description { get; set; } 
     public string Href { get; set; } 
     public FacebookPostType Fb_Object_Type { get; set; } 
     public string Fb_Object_Id { get; set; } 

     [JsonConverter(typeof(FacebookMediaJsonConverter))] 
     public List<FacebookMedia> { get; set; } 

     public string Permalink { get; set; } 
    } 

Sin utilizar FacebookMediaJsonConverter, aparece un error: No se puede deserializar el objeto JSON en el tipo 'System.Collections.Generic.List`1 [FacebookMedia]'. que tiene sentido, ya que en el JSON, Media no es una colección.

me encontré con este post que describe un problema similar, por lo que he intentado ir por este camino: Deserialize JSON, sometimes value is an array, sometimes "" (blank string)

Mi convertidor se ve así:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
{ 
    if (reader.TokenType == JsonToken.StartArray) 
      return serializer.Deserialize<List<FacebookMedia>>(reader); 
    else 
      return null; 
} 

que funciona muy bien, excepto que ahora recibe beneficios una nueva excepción:

Dentro JsonSerializerInternalReader.cs, CreateValueInternal(): símbolo inesperado objeto al deserializar: PropertyName

El valor de reader.Value es "permalink". Puedo ver claramente en el interruptor que no hay ningún caso para JsonToken.PropertyName.

¿Hay algo que deba hacer de manera diferente en mi convertidor? Gracias por cualquier ayuda.

Respuesta

20

el desarrollador de JSON.NET terminó ayudando en el sitio CodePlex proyectos Aquí está la solución:..

el problema fue, cuando era un objeto JSON, no estaba leyendo más allá del atributo. Aquí está el código correcto:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
{ 
    if (reader.TokenType == JsonToken.StartArray) 
    { 
     return serializer.Deserialize<List<FacebookMedia>>(reader); 
    } 
    else 
    { 
     FacebookMedia media = serializer.Deserialize<FacebookMedia>(reader); 
     return new List<FacebookMedia>(new[] {media}); 
    } 
} 

James también tuvo la amabilidad de proporcionar pruebas unitarias para el método anterior.

2

eche un vistazo al espacio de nombres System.Runtime.Serialization en el framework C#, lo llevará a donde desea estar muy rápidamente.

Si lo desea, puede consultar un código de ejemplo en this proyecto (no tratando de conectar mi propio trabajo, pero acabo de terminar casi exactamente lo que está haciendo, pero con un API de fuente diferente.

espero que ayuda

+1

-1 para recommendar el uso de una parte interna probada del marco sobre una biblioteca de terceros con enlaces a muestras de código? – jonezy

+0

que parece muy inusual. – jonezy

+0

No estoy seguro de dónde vino el -1. Aprecio la respuesta. Sospecho que probablemente sea una solución bastante pesada para un problema menor (muy probablemente debido a mi propio uso indebido de JSON.NET). Una vez dicho esto, voy a probar los métodos Systme.Runtime.Serialization y veré si termina funcionando mejor. Gracias por el enlace. – mfanto

-2

Creo que deberías escribir tu clase así ... !!!

public class FacebookAttachment 
    { 

     [JsonProperty("attachment")] 
     public Attachment Attachment { get; set; } 

     [JsonProperty("permalink")] 
     public string Permalink { get; set; } 
    } 

public class Attachment 
    { 

     [JsonProperty("media")] 
     public Media Media { get; set; } 

     [JsonProperty("name")] 
     public string Name { get; set; } 

     [JsonProperty("caption")] 
     public string Caption { get; set; } 

     [JsonProperty("description")] 
     public string Description { get; set; } 

     [JsonProperty("properties")] 
     public Properties Properties { get; set; } 

     [JsonProperty("icon")] 
     public string Icon { get; set; } 

     [JsonProperty("fb_object_type")] 
     public string FbObjectType { get; set; } 
    } 
public class Media 
    { 
    } 
public class Properties 
    { 
    } 
19

Una explicación muy detallada sobre cómo manejar este caso está disponible en "Using a Custom JsonConverter to fix bad JSON results".

En resumen, se puede ampliar el convertidor de JSON.NET predeterminado haciendo

  1. Anotar la propiedad con el tema

    [JsonConverter(typeof(SingleValueArrayConverter<OrderItem>))] 
    public List<OrderItem> items; 
    
  2. Extender el convertidor para devolver una lista de su tipo deseado incluso para un solo objeto

    public class SingleValueArrayConverter<T> : JsonConverter 
    { 
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
        { 
         throw new NotImplementedException(); 
        } 
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
        { 
         object retVal = new Object(); 
         if (reader.TokenType == JsonToken.StartObject) 
         { 
          T instance = (T)serializer.Deserialize(reader, typeof(T)); 
          retVal = new List<T>() { instance }; 
         } else if (reader.TokenType == JsonToken.StartArray) { 
          retVal = serializer.Deserialize(reader, objectType); 
         } 
         return retVal; 
        } 
    
        public override bool CanConvert(Type objectType) 
        { 
         return true; 
        } 
    } 
    

Como se menciona en el artículo, esta extensión no es completamente general, pero funciona si no tiene problemas para obtener una lista.

+0

Absolutamente perfecto. Gracias. – NotMe

+0

estoy confundido - mi WriteJson está lanzando no implementado? ¿Necesito manejar esto? – nologo

Cuestiones relacionadas