2011-05-02 11 views
7

Recibo una excepción cuando intento deserializarme en Silverlight. Test1 falla, mientras que Test2 tiene éxito. También probé TypeNameAssemblyFormat en Simple y Full, pero obtuve los mismos resultados. Test2 puede resolver el ensamblaje, ¿por qué no puede Json.NET?¿Cómo puedo deserializar con TypeNameHandling.Objects en Json.NET Silverlight?

Update: Ha olvidado mencionar que el tipo que estoy tratando de deserializar se define en un ensamblaje diferente del ensamblaje silverlight donde ocurre la deserialización.

Ambas pruebas funcionan en una aplicación .NET no Silverlight.

¿Cómo puedo deserializar una cadena json que tenga nombres tipográficos?

private void Test1() 
{ 
    JsonSerializerSettings settings = new JsonSerializerSettings(); 
    settings.TypeNameHandling = TypeNameHandling.Objects; 
    string json1 = "{\"$type\":\"AmberGIS.NetworkTrace.DTO.NTPoint, NetworkTrace.DTO.Assembly\",\"X\":0.0,\"Y\":0.0,\"SpatialReference\":null}"; 
    try 
    { 
     var n1 = JsonConvert.DeserializeObject<NTPoint>(json1, settings); 
     //Error resolving type specified in JSON 'AmberGIS.NetworkTrace.DTO.NTPoint, NetworkTrace.DTO.Assembly'. 
     //Could not load file or assembly 'NetworkTrace.DTO.Assembly, Culture=neutral, PublicKeyToken=null' or one of its dependencies. 
     //The requested assembly version conflicts with what is already bound in the app domain or specified in the manifest. 
     //(Exception from HRESULT: 0x80131053) 
    } 
    catch (Exception ex) 
    { 
     while (ex != null) 
     { 
      Debug.WriteLine(ex.Message); 
      ex = ex.InnerException; 
     } 
    } 
} 

Este Prueba2 tiene éxito:

private void Test2() 
{ 
    var pnt1 = new AmberGIS.NetworkTrace.DTO.NTPoint(); 
    Debug.WriteLine(pnt1.GetType().AssemblyQualifiedName); 
    // "AmberGIS.NetworkTrace.DTO.NTPoint, NetworkTrace.DTO.Assembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" 

    string fullName = "AmberGIS.NetworkTrace.DTO.NTPoint, NetworkTrace.DTO.Assembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"; 
    var t = Type.GetType(fullName); 
    var pnt2 = Activator.CreateInstance(t) as NTPoint; 

} 
+0

¿por qué no añades su solución como respuesta y lo acepta para que lo haga no aparece en la lista sin respuesta? – keyr

+0

@keyr hecho, pero esperaba una solución menos hacky. –

Respuesta

6

configuración trate de añadir a JsonConvert.DeserializeObject<T>(json, Settings), de que la configuración es:

new JsonSerializerSettings 
       { 
        TypeNameHandling = TypeNameHandling.Objects, 
        TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Full 
       } 
+0

¡Gracias! Has simplificado mucho mi vida. –

+2

Intenté esto y no funcionó. Sigo recibiendo la excepción System.IO.FileLoadException: no se pudo cargar el archivo o ensamblado ... o una de sus dependencias. La versión de ensamblado solicitada entra en conflicto con lo que ya está vinculado en el dominio de la aplicación o especificado en el manifiesto ... Estoy viendo que el problema es que si no se incluye toda la información del ensamblaje, incluida la versión, no funciona. También estoy confundido por qué esto se acepta porque el OP publicó específicamente que el TypeNameAssemblyFormat = FormatterAssemblyStyle.Full no funcionó. –

+0

Oh, Dios mío. Muchas gracias! Tenía la primera parte, pero no sabía sobre TypeNameAssemblyFormat. –

2

resolví mi problema mediante la descarga de fuente para Json.NET 4.0r2, y la adición de 2 líneas de código truco para DefaultSerializationBinder.cs, como se muestra a continuación. Probablemente esto no funcionará para conjuntos nombrados fuertes. Silverlight carece de un método para escanear el dominio de aplicación para conjuntos cargados, consulte here.

#if !SILVERLIGHT && !PocketPC 
     // look, I don't like using obsolete methods as much as you do but this is the only way 
     // Assembly.Load won't check the GAC for a partial name 
#pragma warning disable 618,612 
     assembly = Assembly.LoadWithPartialName(assemblyName); 
#pragma warning restore 618,612 
#else 
      // **next 2 lines are my hack** ... 
      string fullName = String.Format("{0}, {1}, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",typeName,assemblyName); 
      return Type.GetType(fullName); 

     assembly = Assembly.Load(assemblyName); 
#endif 
1

He colgado mi solución a este problema que no requiere la modificación Json.NET:

El problema es que la siguiente línea no es suficiente para Silverlight:

string json1 = "{\"$type\":\"AmberGIS.NetworkTrace.DTO.NTPoint, NetworkTrace.DTO.Assembly\" ... }"; 

Se necesita:

string json1 = "{\"$type\":\"AmberGIS.NetworkTrace.DTO.NTPoint, NetworkTrace.DTO.Assembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null \", ...}"; 

Así que mi forma de incluir que en el JSON (en mi caso el JSON no podía ser cambiado ya que venía de un servidor y no se generó por JSON.net) es manualmente modificar el JSON por iteración sobre todos los objetos (anidados) e insertar la información de montaje:

string json = <some json you want fixed> 
Type type = <the target type you want> 
JObject jsonObject = JObject.parse (json); 
jsonObject["$type"] = type.FullName + ", " + type.Assembly.FullName; 
json = jsonObject.ToString(Formatting.None, null); 

A continuación, puede deserializar como de costumbre utilizando

JsonSerializerSettings settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }; 
var n1 = JsonConvert.DeserializeObject<NTPoint>(json, settings); 
+0

Esta solución funcionó para mí, aunque no me siento cómodo con hackear manualmente el json antes de la deserialización.Creo que otro enfoque podría ser tener un ensamblaje de modelo común con el mismo nombre y tener una versión/versión de Silverlight. – santos

Cuestiones relacionadas