54

JSON.NET ライブラリを使用して Facebook から返されたデータを逆シリアル化するのに少し問題があります。

シンプルなウォール投稿から返される JSON は次のようになります。

{
    "attachment":{"description":""},
    "permalink":"http://www.facebook.com/permalink.php?story_fbid=123456789"
}

写真に対して返される JSON は次のようになります。

"attachment":{
        "media":[
            {
                "href":"http://www.facebook.com/photo.php?fbid=12345",
                "alt":"",
                "type":"photo",
                "src":"http://photos-b.ak.fbcdn.net/hphotos-ak-ash1/12345_s.jpg",
                "photo":{"aid":"1234","pid":"1234","fbid":"1234","owner":"1234","index":"12","width":"720","height":"482"}}
        ],

すべてがうまく機能し、問題はありません。次の JSON を持つモバイル クライアントからの単純なウォール ポストに出くわしました。この 1 つのポストで逆シリアル化が失敗するようになりました。

"attachment":
    {
        "media":{},
        "name":"",
        "caption":"",
        "description":"",
        "properties":{},
        "icon":"http://www.facebook.com/images/icons/mobile_app.gif",
        "fb_object_type":""
    },
"permalink":"http://www.facebook.com/1234"

これが私がデシリアライズしているクラスです:

public class FacebookAttachment
    {
        public string Name { get; set; }
        public string Description { get; set; }
        public string Href { get; set; }
        public FacebookPostType Fb_Object_Type { get; set; }
        public string Fb_Object_Id { get; set; }

        [JsonConverter(typeof(FacebookMediaJsonConverter))]
        public List<FacebookMedia> { get; set; }

        public string Permalink { get; set; }
    }

FacebookMediaJsonConverter を使用しないと、エラーが発生します: JSON オブジェクトを型 'System.Collections.Generic.List`1[FacebookMedia]' に逆シリアル化できません。JSON では Media はコレクションではないため、これは理にかなっています。

同様の問題を説明しているこの投稿を見つけたので、次のルートをたどってみました: JSON をデシリアライズします。値が配列の場合もあれば、"" (空白の文字列) の場合もあります。

私のコンバーターは次のようになります。

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
     if (reader.TokenType == JsonToken.StartArray)
          return serializer.Deserialize<List<FacebookMedia>>(reader);
     else
          return null;
}

新しい例外が発生することを除いて、これは正常に機能します。

JsonSerializerInternalReader.cs、CreateValueInternal() 内: オブジェクトの逆シリアル化中に予期しないトークン: PropertyName

reader.Value の値は「permalink」です。JsonToken.PropertyName のケースがないことがスイッチではっきりとわかります。

コンバーターで別の方法で行う必要があることはありますか? 助けてくれてありがとう。

4

7 に答える 7

45

このケースの処理方法に関する非常に詳細な説明は、「Using a Custom JsonConverter to fix bad JSON results」にあります。

要約すると、デフォルトの JSON.NET コンバーターを次のように拡張できます。

  1. プロパティに問題の注釈を付ける

    [JsonConverter(typeof(SingleValueArrayConverter<OrderItem>))]
    public List<OrderItem> items;
    
  2. コンバーターを拡張して、単一のオブジェクトであっても目的のタイプのリストを返す

    public class SingleValueArrayConverter<T> : JsonConverter
    {
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            object retVal = new Object();
            if (reader.TokenType == JsonToken.StartObject)
            {
                T instance = (T)serializer.Deserialize(reader, typeof(T));
                retVal = new List<T>() { instance };
            } else if (reader.TokenType == JsonToken.StartArray) {
                retVal = serializer.Deserialize(reader, objectType);
            }
            return retVal;
        }
    
        public override bool CanConvert(Type objectType)
        {
            return true;
        }
    }
    

記事で述べたように、この拡張機能は完全に一般的なものではありませんが、リストの取得に問題がなければ機能します。

于 2015-01-26T22:40:58.897 に答える
26

JSON.NET の開発者は、プロジェクトのコードプレックス サイトを支援することになりました。解決策は次のとおりです。

問題は、JSON オブジェクトの場合、属性を読み込んでいないことでした。正しいコードは次のとおりです。

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    if (reader.TokenType == JsonToken.StartArray)
    {
        return serializer.Deserialize<List<FacebookMedia>>(reader);
    }
    else
    {
        FacebookMedia media = serializer.Deserialize<FacebookMedia>(reader);
        return new List<FacebookMedia>(new[] {media});
    }
}

James は親切にも、上記のメソッドの単体テストを提供してくれました。

于 2011-03-08T00:17:05.283 に答える
2

C# フレームワークの System.Runtime.Serialization 名前空間を見てください。目的の場所にすぐにたどり着くことができます。

必要に応じて、このプロジェクトのサンプル コードを確認できます(自分の作業をプラグインしようとしているわけではありませんが、あなたが行っていることとほとんど同じですが、別のソース API を使用しています。

それが役に立てば幸い。

于 2011-03-07T21:00:27.647 に答える
1

。ネットフレームワーク

using Newtonsoft.Json;
using System.IO;   

public Object SingleObjectOrArrayJson(string strJson)
{   
    if(String.IsNullOrEmpty(strJson))
    {
       //Example
       strJson= @"{
        'CPU': 'Intel',
        'PSU': '500W',
        'Drives': [
          'DVD read/writer'
          /*(broken)*/,
          '500 gigabyte hard drive',
          '200 gigabyte hard drive'
        ]
      }";
    }

    JsonTextReader reader = new JsonTextReader(new StringReader(strJson));
    
    //Initialize Read
    reader.Read();
    
        if (reader.TokenType == JsonToken.StartArray)
        {
            return JsonConvert.DeserializeObject<List<Object>>(strJson);
        }
        else
        {
            Object media = JsonConvert.DeserializeObject<Object>(strJson);
            return new List<Object>(new[] {media});
        }
}

注: 「オブジェクト」は、応答の Json 属性に従って定義する必要があります。

于 2021-07-23T02:48:06.943 に答える
-3

このようにクラスを書くべきだと思います...!!!

public class FacebookAttachment
    {

        [JsonProperty("attachment")]
        public Attachment Attachment { get; set; }

        [JsonProperty("permalink")]
        public string Permalink { get; set; }
    }

public class Attachment
    {

        [JsonProperty("media")]
        public Media Media { get; set; }

        [JsonProperty("name")]
        public string Name { get; set; }

        [JsonProperty("caption")]
        public string Caption { get; set; }

        [JsonProperty("description")]
        public string Description { get; set; }

        [JsonProperty("properties")]
        public Properties Properties { get; set; }

        [JsonProperty("icon")]
        public string Icon { get; set; }

        [JsonProperty("fb_object_type")]
        public string FbObjectType { get; set; }
    }
 public class Media
    {
    }
 public class Properties
    {
    }
于 2013-11-29T09:59:42.563 に答える