无法使用Json.NET 8.0.1反序列化具有字节数组属性的对象

在升级代码库以使用Json.NET 8.0.1之后,一些反序列化会失败。 使用Json.NET 7.0.1一切正常。 显然,它是类型为byte[]的属性的反序列化导致了问题。 如果我删除byte[]属性,它工作正常。 我可以使用这个简单的控制台应用程序重现行为:

 internal class Program { private static void Main(string[] args) { Dictionary accounts; var jsonSerializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects, TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple }; using (var streamReader = new StreamReader("accounts.json")) { var json = streamReader.ReadToEnd(); accounts = JsonConvert.DeserializeObject<Dictionary>(json, jsonSerializerSettings); } foreach (var account in accounts) { Debug.WriteLine(account.Value.Name); } } } internal class Account { public string Id { get; set; } public string Name { get; set; } public byte[] EncryptedPassword { get; set; } } 

accounts.json文件如下所示:

 { "$type": "System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[ConsoleApplication1.Account, ConsoleApplication1]], mscorlib", "lars.michael": { "$type": "ConsoleApplication1.Account, ConsoleApplication1", "EncryptedPassword": { "$type": "System.Byte[], mscorlib", "$value": "cGFzc3dvcmQ=" }, "Name": "Lars Michael", "Id": "lars.michael" }, "john.doe": { "$type": "ConsoleApplication1.Account, ConsoleApplication1", "EncryptedPassword": { "$type": "System.Byte[], mscorlib", "$value": "cGFzc3dvcmQ=" }, "Name": "John Doe", "Id": "john.doe" } } 

这可能是Json.NET 8.0.1中的一个错误,还是可以通过调整JsonSerializerSettings解决这个JsonSerializerSettings

如果有人试图重现这一点,请确保将accounts.json文件中的程序集名称与控制台应用程序的程序集名称(在本例中为ConsoleApplication1 )同步。

更新

在更改集70120ce中修复 ,它将包含在Json.NET 8.0.2中。

原始答案

确认 – 这似乎是回归。 考虑以下简单的测试类:

 internal class HasByteArray { public byte[] EncryptedPassword { get; set; } } 

现在,如果我尝试使用TypeNameHandling.Objects对该类进行往返:

  private static void TestSimple() { var test = new HasByteArray { EncryptedPassword = Convert.FromBase64String("cGFzc3dvcmQ=") }; try { TestRoundTrip(test); } catch (Exception ex) { Debug.WriteLine(ex); } } private static void TestRoundTrip(T item) { var jsonSerializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects, TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple }; TestRoundTrip(item, jsonSerializerSettings); } private static void TestRoundTrip(T item, JsonSerializerSettings jsonSerializerSettings) { var json = JsonConvert.SerializeObject(item, Formatting.Indented, jsonSerializerSettings); Debug.WriteLine(json); var item2 = JsonConvert.DeserializeObject(json, jsonSerializerSettings); var json2 = JsonConvert.SerializeObject(item2, Formatting.Indented, jsonSerializerSettings); Debug.WriteLine(json2); if (!JToken.DeepEquals(JToken.Parse(json), JToken.Parse(json2))) throw new InvalidOperationException("Round Trip Failed"); } 

我得到以下exception:

 Newtonsoft.Json.JsonSerializationException: Additional text found in JSON string after finishing deserializing object. at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent) in C:\Development\Releases\Json\Working\Newtonsoft.Json\Working-Signed\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:line 196 at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType) in C:\Development\Releases\Json\Working\Newtonsoft.Json\Working-Signed\Src\Newtonsoft.Json\JsonSerializer.cs:line 823 at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType) in C:\Development\Releases\Json\Working\Newtonsoft.Json\Working-Signed\Src\Newtonsoft.Json\JsonSerializer.cs:line 802 at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings) in C:\Development\Releases\Json\Working\Newtonsoft.Json\Working-Signed\Src\Newtonsoft.Json\JsonConvert.cs:line 863 at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings) in C:\Development\Releases\Json\Working\Newtonsoft.Json\Working-Signed\Src\Newtonsoft.Json\JsonConvert.cs:line 820 at Question34654184.TestClass.TestRoundTrip[T](T item, JsonSerializerSettings jsonSerializerSettings) at Question34654184.TestClass.TestRoundTrip[T](T item) at Question34654184.TestClass.TestSimple() 

Json 7.0中不会发生exception。 您应该报告问题 。

在此期间,您可以使用以下转换器来解决此问题:

 public class ByteArrayConverter : JsonConverter { public override bool CanConvert(Type objectType) { return objectType == typeof(byte[]); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) return null; var token = JToken.Load(reader); if (token == null) return null; switch (token.Type) { case JTokenType.Null: return null; case JTokenType.String: return Convert.FromBase64String((string)token); case JTokenType.Object: { var value = (string)token["$value"]; return value == null ? null : Convert.FromBase64String(value); } default: throw new JsonSerializationException("Unknown byte array format"); } } public override bool CanWrite { get { return false; } } // Use the default implementation for serialization, which is not broken. public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } } 

有了设置

  var jsonSerializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects, TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple, Converters = new [] { new ByteArrayConverter() }, };