使用Json.NET 8.0.1无法反序列化具有字节数组属性的对象 [英] Unable to deserialize an object with a byte array property using Json.NET 8.0.1

查看:68
本文介绍了使用Json.NET 8.0.1无法反序列化具有字节数组属性的对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

After upgrading a code base to use Json.NET 8.0.1, some deserialization stumbles. Using Json.NET 7.0.1 everything works fine. Apparently it is the deserialization of a property of type byte[] that causes the problem. 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; }
}

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来解决此问题吗?

Is this possibly a bug in Json.NET 8.0.1 or can I maybe solve this by tweaking the JsonSerializerSettings?

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

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

推荐答案

更新

已修复在变更集中

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

原始答案

已确认-这似乎是回归.考虑以下简单的测试类:

Confirmed - this appears to be a regression. Consider the following simple test class:

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

现在,如果我尝试使用TypeNameHandling.Objects往返课程:

Now if I try to round-trip the class with 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");
    }

我收到以下异常:

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中不会发生该异常.您应该报告问题.

The exception does not occur in Json 7.0. You should report an issue.

同时,您可以使用以下转换器解决此问题:

In the meantime, you can use the following converter to work around 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();
    }
}

具有设置

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

这篇关于使用Json.NET 8.0.1无法反序列化具有字节数组属性的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆