【发布时间】: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 并再次打开它,代码就可以正常工作。但是如果我再去更改代码(即使我只是添加一个空格),异常就会返回。
【问题讨论】:
-
Newtonsoft 的
DefaultSerializationBinder有一些使用Assembly.LoadWithPartialName(assemblyName);到check the GAC for a partial name的逻辑。也许那是你的问题?尝试在 Linqpad 上调试DefaultSerializationBinder看看会发生什么。如果它不起作用,您可能需要编写一个自定义序列化绑定器,例如来自Custom $type value for serialized objects 的绑定器。 -
出于安全原因,这是一个好主意,请参阅TypeNameHandling caution in Newtonsoft Json 了解原因。
标签: c# json json.net linqpad linqpad6