Unable to deserialize an object using a byte array property using Json.NET 8.0.1

After updating the code base to use Json.NET 8.0.1, some deserializations stumble. Using Json.NET 7.0.1 everything works fine. This is apparently a problem of deserializing a property of type byte[] . If I remove the byte[] property, it works fine. I can reproduce the behavior using this simple console application:

 internal class Program { private static void Main(string[] args) { Dictionary<string, Account> 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<string, Account>>(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; } } 

The accounts.json file is as follows:

 { "$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" } } 

Perhaps this is a bug in Json.NET 8.0.1 or can I solve this problem by setting up JsonSerializerSettings ?

If someone is trying to reproduce this, make sure that you synchronize the assembly name in the accounts.json file with the assembly name of the console application (in this case ConsoleApplication1 ).

+5
source share
1 answer

Update

Fixed in changeset 70120ce , which will be included in Json.NET 8.0.2.

Original answer

Confirmed - this is apparently a regression. Consider the following simple test class:

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

Now, if I try to get around the class using 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>(T item) { var jsonSerializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects, TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple }; TestRoundTrip<T>(item, jsonSerializerSettings); } private static void TestRoundTrip<T>(T item, JsonSerializerSettings jsonSerializerSettings) { var json = JsonConvert.SerializeObject(item, Formatting.Indented, jsonSerializerSettings); Debug.WriteLine(json); var item2 = JsonConvert.DeserializeObject<T>(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"); } 

I get the following 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() 

An exception does not occur in Json 7.0. You must report a problem .

In the meantime, you can use the following converter to solve the problem:

 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(); } } 

With settings

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

Source: https://habr.com/ru/post/1240084/


All Articles