Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
701 views
in Technique[技术] by (71.8m points)

c# - Newtonsoft.Json deserializing base64 image fails

I'm using Newtonsoft.Json to deserialize the output from my webservice to an object. It worked fine until I added a Bitmapproperty to my class (named User) to hold an avatar.

The webservice is returning that propert as a Base64 string, which is as expected. The problem is when I try to convert back the JSON from the WS to a List<User>, a JsonSerializationException is thrown in this block of code:

// 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! 
     });

Output from exception is:

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

and looking at the inner exception:

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

It's clear that it fails to parse the Base64 string, but it's not clear why.

Any ideas/workaround?

EDIT I know I can use Convert.FromBase64String do get a byte array and load a bitmap from that. Then I'd like to update my question to ask about how can I skip or manually parse only that field. I would like to avoid, having to manually parse all the JSON. Is this even possible?

EDIT 2 I found out the root problem: JSON is not being correctly serialized in webservice (and I fail to see why). I thought that this was a somewhat different issue, but no. My webservice is simply returning a string "System.Drawing.Bitmap" instead of its base64 content. Hence the JsonSerializationException.

I have been unable to solve that issue, the only solution I've found is to turn my field into a byte [].

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Read that field as string,

convert to byte array using Convert.FromBase64String and

get the image using Bitmap.FromStream(new MemoryStream(bytearray));

EDIT

You can perform image serialization/deserialization with the help of a custom converter

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());

This is the 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()));
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...