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;
}
NET objects (deserialize) A common way to deserialize JSON is to first create a class with properties and fields that represent one or more of the JSON properties. Then, to deserialize from a string or a file, call the JsonSerializer. Deserialize method.
Deserialization. In Deserialization, it does the opposite of Serialization which means it converts JSON string to custom . Net object. In the following code, it calls the static method DeserializeObject() of the JsonConvert class by passing JSON data. It returns a custom object (BlogSites) from JSON data.
Json.NET is a third party library which helps conversion between JSON text and .
Try adding settings to JsonConvert.DeserializeObject<T>(json, Settings)
,
where Settings is:
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects,
TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Full
}
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
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With