2011-05-02 166 views
7

嘗試在Silverlight中反序列化時出現異常。 Test1失敗,而Test2成功。我也嘗試了TypeNameAssemblyFormat對簡單和完整,但得到相同的結果。 Test2可以解析程序集,爲什麼不能Json.NET?如何使用Json.NET Silverlight中的TypeNameHandling.Objects進行反序列化?

更新:忘了提及我試圖反序列化的類型是在與發生反序列化的silverlight程序集不同的程序集中定義的。

這兩個測試都在非Silverlight .NET應用程序中工作。

如何反序列化具有typenames的json字符串?

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; 

} 
+0

你爲什麼不加入您的解決方案爲答案,接受它:通過遍歷所有(嵌套)對象和插入組件信息修改JSON所以它會沒有出現在沒有答案的列表中? – keyr 2012-12-03 07:36:41

+0

@keyr完成了,但希望得到一個更簡單的解決方案。 – 2012-12-03 15:37:00

回答

6

嘗試增加設置JsonConvert.DeserializeObject<T>(json, Settings), 這裏設置爲:

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

謝謝!你大大簡化了我的生活。 – 2013-02-12 17:23:49

+2

我試過了,它沒有工作。我仍然得到異常System.IO.FileLoadException:無法加載文件或程序集......或其依賴項之一。請求的程序集版本與應用程序域中已經綁定的內容或清單中指定的內容衝突...我發現問題是如果不包括完整程序集信息(包括版本),它不起作用。我也困惑爲什麼這被接受,因爲OP特別發佈了TypeNameAssemblyFormat = FormatterAssemblyStyle.Full不起作用。 – 2014-01-03 16:31:06

+0

我的天啊。非常感謝!我有第一部分,但不知道TypeNameAssemblyFormat。 – 2015-03-26 21:42:18

2

我通過下載源Json.NET 4.0r2,並加入2行的黑客代碼DefaultSerializationBinder.cs,如下圖所示解決了我的問題。這可能不適用於強命名的程序集。 Silverlight缺少掃描加載程序集的appdomain的方法,請參閱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

我在這裏發佈我的解決方案,不需要修改Json.NET:

問題在於以下線對於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生成)的方式是手動

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

這個解決方案對我來說很合適,但我並不習慣在反序列化之前手動破解json。我認爲另一種方法可能是建立一個具有相同名稱的通用模型程序集,並使用它的Silverlight版本/版本。 – santos 2014-08-28 09:31:38