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

8

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;

}
silverlight
json.net
asked on Stack Overflow May 2, 2011 by Kirk Kuykendall • edited Dec 3, 2012 by Kirk Kuykendall

3 Answers

7

Try adding settings to JsonConvert.DeserializeObject<T>(json, Settings), where Settings is:

new JsonSerializerSettings
                {
                    TypeNameHandling = TypeNameHandling.Objects,
                    TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Full
                }
answered on Stack Overflow Dec 28, 2012 by VyvIT
2

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);
#endif
answered on Stack Overflow Dec 3, 2012 by Kirk Kuykendall • edited May 23, 2017 by Community
1

I am posting my solution here that does not require modifying Json.NET:

The problem is that the following line is not sufficient for Silverlight:

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

It needs:

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

So my way of including that in the JSON (in my case the JSON could not be changed since it was coming from a server and wasn't generated by JSON.net) is to manually modify the JSON by iterating over all (nested) objects and inserting the assembly info:

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

Then you can deserialize as usual using

JsonSerializerSettings settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
var n1 = JsonConvert.DeserializeObject<NTPoint>(json, settings);
answered on Stack Overflow Jan 3, 2014 by che javara • edited Jan 3, 2014 by che javara

User contributions licensed under CC BY-SA 3.0