Monday, December 31, 2012

How can I deserialize with TypeNameHandling.Objects in Json.NET Silverlight?

How can I deserialize with TypeNameHandling.Objects in Json.NET Silverlight?

I get an exception when trying to deserialize in Silverlight. Test1 fails, while Test2 succeeds. I've also tried TypeNameAssemblyFormat to both Simple and Full, but get same results. Test2 can resolve the assembly, why can't Json.NET?

Update: Forgot to mention the type I'm trying to deserialize is defined in a different assembly from the silverlight assembly where the deserialization occurs.

Both tests work in a non-silverlight .NET application.

How can I deserialize a json string that has typenames?

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

This Test2 succeeds:

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

Answers & Comments...

Answer: 1

I resolved my issue by downloading source for Json.NET 4.0r2, and adding 2 lines of hack code to DefaultSerializationBinder.cs, as shown below. This probably won't work for strong named assemblies. Silverlight lacks a method to scan the appdomain for loaded assemblies, see 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); 

No comments:

Post a Comment

Send us your comment related to the topic mentioned on the blog