【问题标题】:Types defined in LinqPad cannot be deserialized by Newtonsoft Json serializer在 LinqPad 中定义的类型不能被 Newtonsoft Json 序列化程序反序列化
【发布时间】:2021-07-26 21:39:03
【问题描述】:

我有一个类,我在 Rebus 中用作消息类型来发布/订阅,但是当我在 LinqPad 中尝试概念验证时遇到了障碍。我的应用收到的任何消息都失败并出现反序列化异常。我已经能够将问题缩小到 Newtonsoft.JSON 包并提出最小示例来演示该问题:

public class MyMessage
{
    public string Name { get; set; } = "";
    public int Number { get; set; }
}

void Main()
{
    var message = new MyMessage { Name = "ABC", Number = 5 };
    
    var defaultSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
    
    var serialized = JsonConvert.SerializeObject(message, defaultSettings);
    
    Console.WriteLine(serialized);

    try
    {
        var deserialized = JsonConvert.DeserializeObject(serialized, message.GetType(), defaultSettings);
        Console.WriteLine(deserialized);
    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToString());
    }
}

如果我在 Rider 中编译此代码,它可以作为控制台应用程序正常工作,并将以下内容输出到控制台:

{"$type":"ConsoleApp1.MyMessage, ConsoleApp1","Name":"ABC","Number":5}
ConsoleApp1.MyMessage

相同的代码在 LinqPad 6 中的 JsonConvert.DeserializeObject 语句行失败,并显示以下错误消息:

{"$type":"UserQuery+MyMessage, LINQPadQuery","Name":"ABC","Number":5}
Newtonsoft.Json.JsonSerializationException: Type specified in JSON 'UserQuery+MyMessage, LINQPadQuery, Version=1.0.0.5, Culture=neutral, PublicKeyToken=null' is not compatible with 'UserQuery+MyMessage, LINQPadQuery, Version=1.0.0.61, Culture=neutral, PublicKeyToken=null'. Path '$type', line 1, position 44.
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ResolveTypeName(JsonReader reader, Type& objectType, JsonContract& contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, String qualifiedTypeName)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadMetadataProperties(JsonReader reader, Type& objectType, JsonContract& contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue, Object& newValue, String& id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at UserQuery.Main() in C:\Users\arcaa\AppData\Local\Temp\LINQPad6\_dwfnlfnz\tufqxf\LINQPadQuery:line 19

异常消息:Type specified in JSON 'UserQuery+MyMessage, LINQPadQuery, Version=1.0.0.5, Culture=neutral, PublicKeyToken=null' is not compatible with 'UserQuery+MyMessage, LINQPadQuery, Version=1.0.0.61, Culture=neutral, PublicKeyToken=null

看起来序列化程序试图将字符串反序列化为与作为参数提供的类型 (UserQuery+MyMessage, LINQPadQuery, Version=1.0.0.61) 不同的类型版本 (UserQuery+MyMessage, LINQPadQuery, Version=1.0.0.5)。这里有趣的是JsonConvert.DeserializeObject 方法中使用的类型与传递给序列化程序的类型完全相同,并且该代码中只有一个类。

我不知道其他类型的版本是从哪里来的。有谁知道这是什么原因,如果可能的话,如何避免?

编辑:

我还注意到,如果我关闭 LinqPad 并再次打开它,代码就可以正常工作。但是如果我再去更改代码(即使我只是添加一个空格),异常就会返回。

【问题讨论】:

标签: c# json json.net linqpad linqpad6


【解决方案1】:

Newtonsoft.Json 库中很可能会有一些静态字典,用于缓存类型信息,以字符串为键,例如“MyMessage”。当您编辑查询重新运行它时,LINQPad 必须重新编译查询,因此将有一个新版本的MyMessage 坐在一个新的 DLL 中。但是,Newtonsoft.Json 中的静态缓存仍会指向上次执行时使用的旧缓存。

要解决此问题,您无需重新启动 LINQPad;只需按Shift+F5 即可清除缓存的进程。或者,将以下代码添加到您的查询中:

Util.NewProcess = true;

这告诉 LINQPad 不要缓存该进程以供后续使用。

Edit | 还有一个选项首选项 > 高级以永不回收进程。这会带来很小的性能成本;诸如 LINQPad 的 Util.Cache 之类的方法(在执行之间缓存数据)也将不起作用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多