2011-10-19 15 views
20

Estoy consumiendo algunos servicios web de ARCGis, y tienen algún desafortunado diseño JSON. por ejemplo, podrían dar algo como esto:JSON.NET - Deserialización de tipo condicional

{ 
geometryType: "esriGeometryPolygon" 
geometry: { 
-rings: [ 
-[.blah..... }} 

Ahora, dependiendo del valorGeometryType aprobada en la geometría objeto puede ser uno de varios diferentes tipos de objetos. en el caso anterior, el nodo de geometría es del tipo Polígono.

Entonces, la pregunta es; en JSON.NET ¿hay alguna manera de anotar esta escritura condicional? si no (lo cual dudo que exista), ¿hay alguna forma de crear un proveedor para deserializar ese nodo de geometría, basado en la información del objeto anterior? si no, ¿hay alguna manera recomendada para resolver esto?

edición: i parecía bastante ampliamente en la construcción de un convertidor de costumbre, pero el problema con el convertidor es que tienen este método abstracto:

public override T Create (Type objectType) 

sin embargo, no tengo manera de saber qué tipo de crear aquí , necesito saber qué tipo de objeto se especificó en el JSON anterior.

gracias!

Respuesta

9

Armado un convertidor de muestras para que apunte en la dirección correcta. Aquí están mis cadenas JSON de muestra:

{GeometryType: "esriGeometryPolygon", de geometría: {anillos: 5}}

{GeometryType: "esriGeometryOther", de geometría: {anillos: 5}}

he comprobado como esto:

var serializer = new JsonSerializer(); 
var geometry = serializer.Deserialize<Geometry>(new JsonTextReader(new StringReader(jsonData))); 

//Should have correctly typed instance here... 

y aquí es el convertidor y la geometría de la muestra objetos:

public class GeometryConverter : 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) 
    { 
     if (reader.TokenType == JsonToken.Null) 
      return null; 

     reader.Read(); // startobject 

     //we should be at geometry type property now 
     if ((string)reader.Value != "geometryType") throw new InvalidOperationException(); 

     reader.Read(); //propertyName 

     var type = (string)reader.Value; 

     Geometry value; 

     switch(type) 
     { 
      case "esriGeometryPolygon": 
       value = new PolygonGeometry(); 
       break; 
      case "esriGeometryOther": 
       value = new OtherGeometry(); 
       break; 
      default: 
       throw new NotSupportedException(); 
     } 

     reader.Read(); // move to inner object property 
     //should probably confirm name here 

     reader.Read(); //move to inner object 

     serializer.Populate(reader, value); 

     reader.Read(); //move outside container (should be end object) 

     return value; 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return typeof(Geometry).IsAssignableFrom(objectType); 
    } 
} 

[JsonConverter(typeof(GeometryConverter))] 
public class OtherGeometry : Geometry 
{ 

} 

[JsonConverter(typeof(GeometryConverter))] 
public class PolygonGeometry : Geometry 
{ 

} 

[JsonConverter(typeof(GeometryConverter))] 
public class Geometry 
{ 
    public int rings { get; set; } 
} 
0

que tenía un problema similar y lo resolvió con un JsonSchema, gracias a Yuval Itzchakov 's ayuda: Deserialize json in a “TryParse” way

Parece que algo así:

// Check json schema : 
    const string errorJsonSchema = 
     @"{ 
       'type': 'object', 
       'properties': { 
        'error': {'type':'object'}, 
        'status': {'type': 'string'}, 
        'code': {'type': 'string'} 
       }, 
       'additionalProperties': false 
      }"; 
    JsonSchema schema = JsonSchema.Parse(errorJsonSchema); 
    JObject jsonObject = JObject.Parse(jsonResponse); 
    if (!jsonObject.IsValid(schema)) 
    { 
     error = null; 
     return false; 
    } 

    // Try to deserialize : 
    try 
    { 
     error = new JsonSerializer<Error>.DeserializeFromString(jsonResponse); 
     return true; 
    } 
    catch 
    { 
     // The JSON response seemed to be an error, but failed to deserialize. 
     // This case should not occur... 
     error = null; 
     return false; 
    } 
Cuestiones relacionadas