我正在使用Newtonsoft.Json将我的webservice的输出反序列化为一个对象。
它工作正常,直到我向我的班级(名为Bitmap
)添加User
属性来持有头像。
webservice将该属性作为Base64字符串返回,这是预期的。
问题是当我尝试将JSON从WS转换回List<User>
时,在这段代码中抛出JsonSerializationException
:
// T is IList<User>
response.Content.ReadAsStringAsync().Proceed(
(readTask) =>
{
var json = ((Task<string>)readTask).Result;
var result = JsonConvert.DeserializeObject<T>(json); //<-- it fails here
// do stuff!
});
例外的输出是:
Error converting value "System.Drawing.Bitmap" to type 'System.Drawing.Bitmap'. Path '[2].Avatar
并查看内部异常:
{"Could not cast or convert from System.String to System.Drawing.Bitmap."}
很明显,它无法解析Base64字符串,但目前尚不清楚原因。
任何想法/解决方法?
修改
我知道我可以使用Convert.FromBase64String
获取一个字节数组并从中加载一个位图。然后我想更新我的问题,询问如何我可以跳过或手动解析 该字段。
我想避免,不得不手动解析所有JSON。
这甚至可能吗?
编辑2
我发现了根本问题:在Web服务中没有正确地序列化JSON(我没有看到原因)。我认为this是一个有点不同的问题,但没有。我的webservice只是返回一个字符串"System.Drawing.Bitmap"
而不是它的base64内容。因此JsonSerializationException
。
我一直无法解决这个问题,我找到的唯一解决办法是将我的字段变为byte []
。
答案 0 :(得分:10)
将该字段读为字符串,
使用Convert.FromBase64String
和
使用Bitmap.FromStream(new MemoryStream(bytearray));
修改强>
您可以借助自定义转换器
执行图像序列化/反序列化public class AClass
{
public Bitmap image;
public int i;
}
Bitmap bmp = (Bitmap)Bitmap.FromFile(@"......");
var json = JsonConvert.SerializeObject(new AClass() { image = bmp, i = 666 },
new ImageConverter());
var aclass = JsonConvert.DeserializeObject<AClass>(json, new ImageConverter());
这是ImageConverter
public class ImageConverter : Newtonsoft.Json.JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Bitmap);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var m = new MemoryStream(Convert.FromBase64String((string)reader.Value));
return (Bitmap)Bitmap.FromStream(m);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Bitmap bmp = (Bitmap)value;
MemoryStream m = new MemoryStream();
bmp.Save(m, System.Drawing.Imaging.ImageFormat.Jpeg);
writer.WriteValue(Convert.ToBase64String(m.ToArray()));
}
}
答案 1 :(得分:6)
这是我的解决方案,我使用了注释
[Serializable]
public class MyClass
{
[JsonConverter(typeof(CustomBitmapConverter))]
public Bitmap MyImage { get; set; }
#region JsonConverterBitmap
internal class CustomBitmapConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return true;
}
//convert from byte to bitmap (deserialize)
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
string image = (string)reader.Value;
byte[] byteBuffer = Convert.FromBase64String(image);
MemoryStream memoryStream = new MemoryStream(byteBuffer);
memoryStream.Position = 0;
return (Bitmap)Bitmap.FromStream(memoryStream);
}
//convert bitmap to byte (serialize)
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Bitmap bitmap = (Bitmap)value;
ImageConverter converter = new ImageConverter();
writer.WriteValue((byte[])converter.ConvertTo(bitmap, typeof(byte[])));
}
public static System.Drawing.Imaging.ImageFormat GetImageFormat(Bitmap bitmap)
{
ImageFormat img = bitmap.RawFormat;
if (img.Equals(System.Drawing.Imaging.ImageFormat.Jpeg))
return System.Drawing.Imaging.ImageFormat.Jpeg;
if (img.Equals(System.Drawing.Imaging.ImageFormat.Bmp))
return System.Drawing.Imaging.ImageFormat.Bmp;
if (img.Equals(System.Drawing.Imaging.ImageFormat.Png))
return System.Drawing.Imaging.ImageFormat.Png;
if (img.Equals(System.Drawing.Imaging.ImageFormat.Emf))
return System.Drawing.Imaging.ImageFormat.Emf;
if (img.Equals(System.Drawing.Imaging.ImageFormat.Exif))
return System.Drawing.Imaging.ImageFormat.Exif;
if (img.Equals(System.Drawing.Imaging.ImageFormat.Gif))
return System.Drawing.Imaging.ImageFormat.Gif;
if (img.Equals(System.Drawing.Imaging.ImageFormat.Icon))
return System.Drawing.Imaging.ImageFormat.Icon;
if (img.Equals(System.Drawing.Imaging.ImageFormat.MemoryBmp))
return System.Drawing.Imaging.ImageFormat.MemoryBmp;
if (img.Equals(System.Drawing.Imaging.ImageFormat.Tiff))
return System.Drawing.Imaging.ImageFormat.Tiff;
else
return System.Drawing.Imaging.ImageFormat.Wmf;
}
}
#endregion
答案 2 :(得分:1)
我认为不支持从Base64
到System.Drawing.Bitmap
的反序列化。也许你可以尝试反序列化除Avatar
属性
编辑已编辑的问题
以下是关于如何做到这一点的有趣讨论: JSON.Net Ignore Property during deserialization
我认为你能做的最好就是使用Regex
从json字符串中删除属性:
var newJsonString = Regex.Replace(jsonString,
"(\\,)* \"Avatar\": \"[A-Za-z0-9]+\"",
String.Empty);
然后在没有Avatar属性的情况下反序列化此newJsonString
。
稍后您可以解析原始json字符串以获取base64
并构建Bitmap
var avatarBase64 = Regex.Match(
Regex.Match(json, "(\\,)* \"Avatar\": \"[A-Za-z0-9]+\"")
.ToString(),
"[A-Za-z0-9]+", RegexOptions.RightToLeft)
.ToString();
...
byte[] fromBase64 = Convert.FromBase64String(avatarBase64);
using (MemoryStream ms = new MemoryStream(fromBase64))
{
Bitmap img = (Bitmap)Image.FromStream(ms);
result.Avatar = img;
}
你可以改进正则表达式或方法,但这是基本的想法。