C# Json反序列化base64映像失败
我正在使用Newtonsoft.Json将Web服务的输出反序列化为对象。 在我将C# Json反序列化base64映像失败,c#,.net,json,image,C#,.net,Json,Image,我正在使用Newtonsoft.Json将Web服务的输出反序列化为对象。 在我将位图属性添加到我的类(名为用户)中以保存化身之前,它工作得很好 webservice正在以Base64字符串的形式返回该属性,这与预期的一样。 问题是,当我尝试将JSON从WS转换回列表时,会在这段代码中抛出JsonSerializationException: // T is IList<User> response.Content.ReadAsStringAsync().Proceed( (
位图
属性添加到我的类(名为用户
)中以保存化身之前,它工作得很好
webservice正在以Base64字符串的形式返回该属性,这与预期的一样。
问题是,当我尝试将JSON从WS转换回列表时,会在这段代码中抛出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!
});
看看内部异常:
{"Could not cast or convert from System.String to System.Drawing.Bitmap."}
很明显,它无法解析Base64字符串,但不清楚原因
有什么想法/解决方法吗
编辑
我知道我可以使用Convert.FromBase64String
获取字节数组并从中加载位图。然后我想更新我的问题,询问如何跳过或手动解析该字段。
我希望避免手动解析所有JSON。
这可能吗
编辑2
我发现了根本问题:JSON在webservice中没有被正确序列化(我不明白为什么)。我认为这是一个有点不同的问题,但不是。我的Web服务只是返回一个字符串“System.Drawing.Bitmap”
,而不是它的base64内容。因此出现了JsonSerializationException
我一直无法解决这个问题,我找到的唯一解决办法是将我的字段转换为字节[]
将该字段读取为字符串
使用convert.FromBase64String
和
使用Bitmap.FromStream(newmemorystream(bytearray))获取图像代码>
编辑
您可以在自定义转换器的帮助下执行图像序列化/反序列化
我认为不支持从Base64
反序列化到System.Drawing.Bitmap
。可能您可以尝试反序列化除Avatar
属性之外的所有内容
编辑已编辑的问题
下面是一个关于如何做到这一点的有趣讨论:
我认为您最好使用Regex
从json字符串中删除属性:
var newJsonString = Regex.Replace(jsonString,
"(\\,)* \"Avatar\": \"[A-Za-z0-9]+\"",
String.Empty);
然后反序列化这个newJsonString
,而不使用Avatar属性
稍后,您可以解析原始json字符串以获取base64
,并构建位图
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;
}
您可以改进正则表达式或方法,但这是基本思想。这是我的解决方案,我使用了注释
[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
请参考我编辑的问题。有没有办法让JsonConvert.DeserializeObject(json)
只跳过一个字段?这是在一个通用方法中,因此我希望避免完全手动解析…使用此代码,我必须手动序列化Web服务中的对象,对吗?@Joel no。如果字段/属性的类型为Bitmap
,则此代码将base64编码字符串反序列化为位图。请参阅AClass的定义
请参阅我的更新。你的解决方案很有希望,但我无法测试它,因为根本问题已经改变了。如果我解决了这个问题,我一定会测试你的解决方案。@Joel只需使用JsonConvert.SerializeObject(你的对象,new ImageConverter())代码>“您可以尝试反序列化除Avatar属性之外的所有内容…”有没有一种方法可以做到这一点而不必手动解析所有元素?a)Base64编码需要64个字符,但我在这个正则表达式中只看到62个a-Za-z0-9
b)尝试用正则表达式解析json并不好。c) “我认为不支持从Base64反序列化到System.Drawing.Bitmap。”不正确。d) 您可以将avatar
字段声明为字符串,并在不使用正则表达式的情况下用c#构建图像。
var newJsonString = Regex.Replace(jsonString,
"(\\,)* \"Avatar\": \"[A-Za-z0-9]+\"",
String.Empty);
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;
}
[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