4

iOS クライアント (Monotouch) で API サーバーから送信された json ファイルを逆シリアル化するために Json.NET を使用しています。逆シリアル化がランダムな例外で失敗することがあるため、私は本当に奇妙な問題を抱えています。以前は何の問題もありませんでしたが、jsonファイルが大きくなってから始まったと思います。それが発生した場合、アプリケーションに再試行するように依頼するだけで、ランダムな回数 (およびさまざまな例外をランダム化) した後、デシリアライゼーションは理由もなく最終的に機能します。

私が得たさまざまな例外は次のとおりです。

  2013-02-12 19:14:58.307 client_ios[2176:4303] Failed to deserialize: Unexpected end of content while loading JObject.  
        at Newtonsoft.Json.Linq.JContainer.ReadTokenFrom (Newtonsoft.Json.JsonReader r) [0x00000] in <filename unknown>:0 
        at Newtonsoft.Json.Linq.JObject.Load (Newtonsoft.Json.JsonReader reader) [0x00000] in <filename unknown>:0 
        at shared.api.NotificationConverter.ReadJson (Newtonsoft.Json.JsonReader reader, System.Type objectType, System.Object existingValue, Newtonsoft.Json.JsonSerializer serializer) [0x00000] in /Users/xxx/Projects/xxx/shared/src/api/Notification.cs:23 
        at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueNonProperty (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract) [0x00000] in <filename unknown>:0 
        at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList (IWrappedCollection wrappedList, Newtonsoft.Json.JsonReader reader, System.String reference, Newtonsoft.Json.Serialization.JsonArrayContract contract) [0x00000] in <filename unknown>:0 

Failed to deserialize: Unterminated string. Expected delimiter: ". Line 2530, position 69.  at Newtonsoft.Json.JsonTextReader.ReadStringIntoBuffer (Char quote) [0x00000] in <filename unknown>:0 
  at Newtonsoft.Json.JsonTextReader.ParseString (Char quote) [0x00000] in <filename unknown>:0 
  at Newtonsoft.Json.JsonTextReader.ParseValue (Char currentChar) [0x00000] in <filename unknown>:0 
  at Newtonsoft.Json.JsonTextReader.ReadInternal () [0x00000] in <filename unknown>:0 
  at Newtonsoft.Json.JsonTextReader.Read () [0x00000] in <filename unknown>:0 
  at Newtonsoft.Json.Linq.JContainer.ReadContentFrom (Newtonsoft.Json.JsonReader r) [0x00000] in <filename unknown>:0 
  at Newtonsoft.Json.Linq.JContainer.ReadTokenFrom (Newtonsoft.Json.JsonReader r) [0x00000] in <filename unknown>:0 
  at Newtonsoft.Json.Linq.JObject.Load (Newtonsoft.Json.JsonReader reader) [0x00000] in <filename unknown>:0 
  at shared.api.NotificationConverter.ReadJson (Newtonsoft.Json.JsonReader reader, System.Type objectType, System.Object existingValue, Newtonsoft.Json.JsonSerializer serializer) [0x00000] in /Users/xxx/Projects/xxx/shared/src/api/Notification.cs:23 
  at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueNonProperty (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract) [0x00000] in <filename unknown>:0 
  at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList (IWrappedCollection wrappedList, Newtonsoft.Json.JsonReader reader, System.String reference,     Newtonsoft.Json.Serialization.JsonArrayContract contract) [0x00000] in <filename unknown>:0 

デシリアライズに使用するいくつかの行を次に示します。

using (WebResponse webResponse = requestWeb.GetResponse()) {
    using (Stream responseStream = webResponse.GetResponseStream()) {
        using (StreamReader streamReader = new StreamReader(responseStream)) {
            using (JsonReader jsonReader = new JsonTextReader(streamReader)) {
                JsonSerializer serializer = new JsonSerializer();
                serializer.Converters.Add(creator);
                rsp = serializer.Deserialize<SimpleServerResponse>(jsonReader);
            }
        }
     }
}

JObject.Load(reader) でクラッシュします。

public class NotificationConverter : JsonConverter {

    public override bool CanConvert(Type objectType) {
        return typeof(ANotification).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
        JObject jobject = JObject.Load(reader);

        object target = null;

        JToken token = jobject["type_id"];

        if (token != null) {
            int id = token.ToObject<int>();

            switch (id) {
                case ANotification.STORY_INVITE:
                    target = new Notification<Moment>();
                    break;
                case ANotification.STORY_CONTENT_ADDED:
                    target = new Notification<Moment>();
                    break;
                case ANotification.STORY_LIKE:
                    target = new Notification<Moment>();
                    break;
                case ANotification.PICTURE_COMMENTED:
                    target = new Notification<PictureMomentPair>();
                    break;
                case ANotification.PICTURE_LIKED:
                    target = new Notification<PictureMomentPair>();
                    break;
                case ANotification.USER_FOLLOW:
                    target = new Notification<User>();
                    break;
                default:
                    break;
            }

            serializer.Populate(jobject.CreateReader(), target);
        }

        return target;
    }
}

私の JsonConverter に関するいくつかの説明: JSON ファイルでサーバーによって送信されるオブジェクトは、「type_id」の値に応じて変更される場合があります。JsonConverter は type_id を読み取り、それに応じて正しいオブジェクトを返そうとします。

現時点での私の回避策は、ストリーム全体を文字列で読み取り、それを json デシリアライザーに渡すことですが、iOS では明らかに遅くなります (より多くの CPU を消費します)。

なぜそれが機能する場合と機能しない場合があるのか​​ わかりません。

4

0 に答える 0