反序列化的base64 EN codeD字节数组返回不同的结果在2 JSON.net库版本数组、字节、不同、版本

2023-09-04 12:58:50 作者:本王不退位尔等都是臣

  JObject j = JObject.Parse("{'responseArray':'AAAAAAAAAAAAAAAAAAAAAAAAAAABAAAA'}");

  byte[] r = j["responseArray"].ToObject<byte[]>(JsonSerializer.Create(new JsonSerializerSettings()));

预计产量(正常工作与JSON.net v4.5.6.14930)

Expected Output (works fine with JSON.net v4.5.6.14930)

r =  {byte[24]}
        [0]: 0
        [1]: 0
        [2]: 0
        [3]: 0
        [4]: 0
        [5]: 0
        [6]: 0
        [7]: 0
        [8]: 0
        [9]: 0
        [10]: 0
        [11]: 0
        [12]: 0
        [13]: 0
        [14]: 0
        [15]: 0
        [16]: 0
        [17]: 0
        [18]: 0
        [19]: 0
        [20]: 1
        [21]: 0
        [22]: 0
        [23]: 0

反序列化上面的code在JSON.net v6.0.8.18111给errorneous结果

Deserializing the above code in JSON.net v6.0.8.18111 gives errorneous result

错误输出(JSON.net v6.0.8.18111)

Incorrect Output (JSON.net v6.0.8.18111)

r= {byte[16]}
    [0]: 170
    [1]: 170
    [2]: 170
    [3]: 170
    [4]: 170
    [5]: 170
    [6]: 170
    [7]: 170
    [8]: 170
    [9]: 170
    [10]: 170
    [11]: 170
    [12]: 170
    [13]: 171
    [14]: 170
    [15]: 170

难道我做错了吗?

Am I doing something wrong here?

注意 - 在这个问题的片段是一个复杂的code,其中的数据来作为JSON参数一个WebMethod的一部分,responsearray送入WebMethod的复杂对象的一部分,这就是为什么我们使用JSON。网库解码。

Note- The snippet in the question is part of a complex piece of code, where data comes in as JSON parameter to a WebMethod, The responsearray is a part of a complex object sent into the webmethod, that is why we use the JSON.net library for decoding.

推荐答案

更新

这是固定在 Json.NET 7.0版本1 。

原来的答案

这是一个Json.NET问题。问题是,你的字符串 AAAAAAAAAAAAAAAAAAAAAAAAAAABAAAA 恰好是成功可解析为一个GUID,在的 JsonReader.ReadAsBytesInternal()

This is a Json.NET issue. The problem is that your string AAAAAAAAAAAAAAAAAAAAAAAAAAABAAAA just happens to be successfully parsable as a GUID, in JsonReader.ReadAsBytesInternal():

            if (s.Length == 0)
            {
                data = new byte[0];
            }
            else if (ConvertUtils.TryConvertGuid(s, out g))
            {
                data = g.ToByteArray();
            }
            else
            {
                data = Convert.FromBase64String(s);
            }

目前回溯:

Newtonsoft.Json.JsonReader.ReadAsBytesInternal() Line 517   C#
Newtonsoft.Json.Linq.JTokenReader.ReadAsBytes() Line 74 + 0x9 bytes C#
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadForType(Newtonsoft.Json.JsonReader reader = {Newtonsoft.Json.Linq.JTokenReader}, Newtonsoft.Json.Serialization.JsonContract contract = {Newtonsoft.Json.Serialization.JsonPrimitiveContract}, bool hasConverter = false) Line 1853 + 0x8 bytes   C#
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(Newtonsoft.Json.JsonReader reader = {Newtonsoft.Json.Linq.JTokenReader}, System.Type objectType = {Name = "Byte[]" FullName = "System.Byte[]"}, bool checkAdditionalContent = false) Line 144 + 0x2f bytes   C#
Newtonsoft.Json.JsonSerializer.DeserializeInternal(Newtonsoft.Json.JsonReader reader = {Newtonsoft.Json.Linq.JTokenReader}, System.Type objectType = {Name = "Byte[]" FullName = "System.Byte[]"}) Line 710 + 0x52 bytes    C#
Newtonsoft.Json.JsonSerializer.Deserialize(Newtonsoft.Json.JsonReader reader = {Newtonsoft.Json.Linq.JTokenReader}, System.Type objectType = {Name = "Byte[]" FullName = "System.Byte[]"}) Line 689 + 0x11 bytes    C#
Newtonsoft.Json.Linq.JToken.ToObject(System.Type objectType = {Name = "Byte[]" FullName = "System.Byte[]"}, Newtonsoft.Json.JsonSerializer jsonSerializer = {Newtonsoft.Json.JsonSerializer}) Line 1837 + 0x11 bytes    C#
Newtonsoft.Json.Linq.JToken.ToObject(System.Type objectType = {Name = "Byte[]" FullName = "System.Byte[]"}) Line 1811 + 0x3c bytes  C#
Newtonsoft.Json.Linq.JToken.ToObject<byte[]>() Line 1698 + 0x39 bytes   C#

正如你所看到的,这种短路基地64解码。丑陋的错误,并在你的一部分,而运气不好来获取精确的字符串。

As you can see, this short-circuits the base 64 decoding. Ugly bug, and rather bad luck on your part to get that exact string.

要阻止Json.NET的不适当的GUID识别您可以创建自己的全球 JsonConverter 字节数组。当你这样做,Json.NET会传给你没有有用的GUID模式匹配的原始字符串:

To block Json.NET's inappropriate GUID recognition you can create your own global JsonConverter for byte arrays. When you do, Json.NET will pass you the raw string without the "helpful" GUID pattern match:

public class ByteConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(byte[]);
    }

    public override bool CanWrite { get { return false; } } // Use the default implementation for serialization, which is not broken.

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var value = (string)JToken.Load(reader);
        if (value == null)
            return null;
        if (value.Length == 0)
            return new byte[0];
        return Convert.FromBase64String(value);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

随后,在全局设置:

And then, to set it globally:

        JsonConvert.DefaultSettings = () => new JsonSerializerSettings
        {
            Converters = new List<JsonConverter> { new ByteConverter() }
        };

这个解决方法恢复正确的反序列化的字节数组。

This workaround restores the correct deserialization for byte arrays.