如何在Json.NET Silverlight中使用TypeNameHandling.Objects反序列化?

时间:2011-05-02 17:54:19

标签: silverlight json.net

尝试在Silverlight中反序列化时出现异常。 Test1失败,而Test2成功。我也尝试将TypeNameAssemblyFormat同时用于Simple和Full,但得到相同的结果。 Test2可以解决程序集,为什么不能Json.NET?

更新:忘记提及我尝试反序列化的类型是在与反序列化发生的silverlight程序集不同的程序集中定义的。

这两个测试都适用于非Silverlight .NET应用程序。

如何反序列化具有类型名的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;

}

3 个答案:

答案 0 :(得分:7)

尝试将设置添加到JsonConvert.DeserializeObject<T>(json, Settings), 设置为:

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

答案 1 :(得分:2)

我通过下载Json.NET 4.0r2的源代码并向DefaultSerializationBinder.cs添加2行黑客代码解决了我的问题,如下所示。这可能不适用于强名称程序集。 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

答案 2 :(得分: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生成而无法更改)是通过遍历所有来手动修改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);
相关问题