6

Newtonsoft.Jsonを使用して、Webサービスからオブジェクトへの出力を逆シリアル化します。アバターを保持するためのBitmapプロパティ(という名前)をクラスに追加するまでは、問題なく機能しました。User

Webサービスは、そのプロパティをBase64文字列として返します。これは予想どおりです。問題は、JSONをWSからaに変換し直そうとすると、次のコードブロックでList<User>aがスローされることです。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 根本的な問題を発見しました:JSONがWebサービスで正しくシリアル化されていません(そしてその理由がわかりません)。これは少し違う問題だと思いましたが、違います。"System.Drawing.Bitmap"私のWebサービスは、base64コンテンツの代わりに文字列を返すだけです。したがって、JsonSerializationException

私はその問題を解決することができませんでした、私が見つけた唯一の解決策は私のフィールドをに変えることbyte []です。

4

3 に答える 3

11

そのフィールドを文字列として読み取り、

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()));
    }
}
于 2013-03-19T21:35:11.100 に答える
7

これが私の解決策です、私は注釈を使用しました

[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
于 2013-07-26T08:38:04.370 に答える
0

Base64toからの逆シリアル化System.Drawing.Bitmapはサポートされていないと思います。Avatarプロパティ以外のすべてを逆シリアル化してみることができるかもしれません

編集された質問のために編集

これを行う方法に関する興味深い議論があります: JSON.Netは逆シリアル化中にプロパティを無視します

私はあなたができる最善のことはRegexjson文字列からプロパティを削除するために使用することだと思います:

var newJsonString = Regex.Replace(jsonString, 
                                  "(\\,)* \"Avatar\": \"[A-Za-z0-9]+\"", 
                                  String.Empty);

newJsonString次に、Avatarプロパティなしでこれを逆シリアル化します。

後で、元の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;
}

正規表現やメソッドを改善することもできますが、それが基本的な考え方です。

于 2013-03-19T21:35:38.943 に答える