当我试图在Silverlight中反序列化时,我得到了一个异常。Test1失败,Test2成功。我也尝试过TypeNameAssemblyFormat简单和完整,但得到相同的结果。Test2可以解析程序集,为什么Json.NET不能?
Update:忘了提到我试图反序列化的类型是在与反序列化发生的silverlight程序集不同的程序集中定义的。
两个测试都可以在非silverlight . net应用程序中运行。
我如何反序列化一个json字符串有typennames ?
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;
}
}
}
这个Test2成功:
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;
}
尝试为JsonConvert.DeserializeObject<T>(json, Settings)
添加设置,其中Settings为:
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects,
TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Full
}
我通过下载Json源代码解决了我的问题。. NET 4.0r2,并向DefaultSerializationBinder.cs添加2行hack代码,如下所示。这可能不适用于强命名程序集。Silverlight缺少一种方法来扫描appdomain中加载的程序集,见这里。
#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
我在这里张贴我的解决方案,不需要修改Json。净:
问题是以下行对于Silverlight来说是不够的:
string json1 = "{"$type":"AmberGIS.NetworkTrace.DTO.NTPoint, NetworkTrace.DTO.Assembly" ... }";
需要:
string json1 = "{"$type":"AmberGIS.NetworkTrace.DTO.NTPoint, NetworkTrace.DTO.Assembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null ", ...}";
所以我的方式包括JSON(在我的情况下JSON不能改变,因为它来自服务器,不是由JSON.net生成)是手动修改JSON通过迭代所有(嵌套)对象和插入汇编信息:
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);
然后可以像往常一样使用
反序列化JsonSerializerSettings settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
var n1 = JsonConvert.DeserializeObject<NTPoint>(json, settings);