Newtonsoft.Json反序列化base64图像失败

我正在使用Newtonsoft.Json将我的webservice的输出反序列化为一个对象。 它工作正常,直到我将一个Bitmap属性添加到我的类(名为User )来持有一个头像。

web服务将该属性作为Base64字符串返回,这是预期的。 问题是当我尝试将JSON从WS转换回List ,会在此代码块中抛出JsonSerializationException

 // T is IList response.Content.ReadAsStringAsync().Proceed( (readTask) => { var json = ((Task)readTask).Result; var result = JsonConvert.DeserializeObject(json); //<-- it fails here // do stuff! }); 

exception输出是:

 Error converting value "System.Drawing.Bitmap" to type 'System.Drawing.Bitmap'. Path '[2].Avatar 

并查看内部exception:

 {"Could not cast or convert from System.String to System.Drawing.Bitmap."} 

很明显,它无法解析Base64字符串,但目前尚不清楚原因。

任何想法/解决方法?

编辑我知道我可以使用Convert.FromBase64String来获取一个字节数组并从中加载一个位图。 然后我想更新我的问题,询问我如何跳过或手动解析该字段。 我想避免,不得不手动解析所有JSON。 这有可能吗?

编辑2我发现了根本问题:在Web服务中没有正确序列化JSON(我没有看到原因)。 我认为这是一个有点不同的问题,但没有。 我的webservice只是返回一个字符串"System.Drawing.Bitmap"而不是它的base64内容。 因此JsonSerializationException

我一直无法解决这个问题,我发现的唯一解决方案是将我的字段转换为byte []

将该字段读为字符串,

使用Convert.FromBase64String和转换为字节数组

使用Bitmap.FromStream(new MemoryStream(bytearray));获取图像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(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())); } } 

这是我的解决方案,我使用了注释

 [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 

我认为不支持从Base64System.Drawing.Bitmap的反序列化。 也许你可以尝试反序列化除Avatar属性之外的所有东西

编辑编辑问题

以下是有关如何执行此操作的有趣讨论: 反序列化期间JSON.Net忽略属性

我认为你能做的最好的就是使用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; } 

你可以改进正则表达式或方法,但这是基本的想法。