C# 无法使用Json.NET 8.0.1反序列化具有字节数组属性的对象
在将代码库升级为使用Json.NET 8.0.1之后,一些反序列化遇到了问题。使用Json.NET7.0.1,一切正常。显然,是类型为C# 无法使用Json.NET 8.0.1反序列化具有字节数组属性的对象,c#,serialization,json.net,C#,Serialization,Json.net,在将代码库升级为使用Json.NET 8.0.1之后,一些反序列化遇到了问题。使用Json.NET7.0.1,一切正常。显然,是类型为byte[]的属性的反序列化导致了问题。如果我删除byte[]属性,它可以正常工作。我可以使用这个简单的控制台应用程序重现该行为: internal class Program { private static void Main(string[] args) { Dictionary<string, Account>
byte[]
的属性的反序列化导致了问题。如果我删除byte[]
属性,它可以正常工作。我可以使用这个简单的控制台应用程序重现该行为:
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; }
}
这可能是Json.NET 8.0.1中的一个bug,或者我可以通过调整JsonSerializerSettings
来解决这个问题吗
如果有人试图复制此内容,请确保将
accounts.json
文件中的程序集名称与控制台应用程序的程序集名称同步(在本例中为控制台应用程序1
)。更新
在变更集中,将包含在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>(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");
}
Json 7.0中没有出现异常。你应该
同时,您可以使用以下转换器解决此问题:
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() },
};
酷,谢谢你的确认和解决方法。我已经在GitHub上报告了这个问题。
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() },
};