Deserializing JSON, когда иногда массивы, а иногда и объекты

У меня возникли проблемы с десериализацией данных, полученных из Facebook с использованием библиотек JSON.NET.

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://sofru.miximages.com/c%23/12345_s.jpg", "photo":{"aid":"1234","pid":"1234","fbid":"1234","owner":"1234","index":"12","width":"720","height":"482"}} ], 

Все отлично работает, и у меня нет проблем. Теперь я столкнулся с простым стеновым сообщением от мобильного клиента со следующим JSON, и теперь десериализация не выполняется с одной единственной записью:

 "attachment": { "media":{}, "name":"", "caption":"", "description":"", "properties":{}, "icon":"http://sofru.miximages.com/c%23/mobile_app.gif", "fb_object_type":"" }, "permalink":"http://www.facebook.com/1234" 

Вот class, который я десериализую как:

 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 { get; set; } public string Permalink { get; set; } } 

Без использования FacebookMediaJsonConverter я получаю сообщение об ошибке: не удается десериализовать объект JSON в тип «System.Collections.Generic.List`1 [FacebookMedia]». что имеет смысл, поскольку в JSON Media не является коллекцией.

Я нашел этот пост, который описывает аналогичную проблему, поэтому я попытался спуститься по этому маршруту: Deserialize JSON, иногда значение представляет собой массив, иногда «” (пустая строка)

Мой конвертер выглядит так:

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

Это работает отлично, но теперь я получаю новое исключение:

Inside JsonSerializerInternalReader.cs, CreateValueInternal (): Неожиданный токен при десериализации объекта: PropertyName

Значение reader.Value является «permalink». Я могу ясно видеть в коммутаторе, что нет никакого случая для JsonToken.PropertyName.

Есть что-то, что мне нужно сделать по-другому в моем конвертере? Спасибо за любую помощь.

Очень подробное объяснение того, как справиться с этим случаем, доступно в разделе «Использование пользовательского JsonConverter для исправления плохих результатов JSON» .

Подводя итог, вы можете расширить конвертер JSON.NET по умолчанию

  1. Аннотировать свойство с вопросом

     [JsonConverter(typeof(SingleValueArrayConverter))] public List items; 
  2. Расширьте конвертер, чтобы вернуть список нужного вам типа даже для одного объекта

     public class SingleValueArrayConverter : 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() { instance }; } else if (reader.TokenType == JsonToken.StartArray) { retVal = serializer.Deserialize(reader, objectType); } return retVal; } public override bool CanConvert(Type objectType) { return true; } } 

Как упоминалось в этой статье, это расширение не является полностью общим, но оно работает, если вы в порядке с получением списка.

Разработчик JSON.NET оказывал помощь на сайте codeplex проектов. Вот решение:

Проблема заключалась в том, что когда это был объект JSON, я не читал атрибут. Вот правильный код:

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

Джеймс также был достаточно любезен, чтобы предоставить единичные тесты для вышеуказанного метода.

взгляните на пространство имен System.Runtime.Serialization в инфраструктуре c #, это приведет вас к тому, где вы хотите быть очень быстрым.

Если вы хотите, вы можете проверить код примера в этом проекте (не пытаясь подключить мою собственную работу, но я только что закончил в точности то, что вы делаете, но с другим исходным api.

Надеюсь, поможет.

Я думаю, вы должны написать свой class, как это … !!!

 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 { } 
  • Можете ли вы определить, был ли объект, десериализованный объект, отсутствием поля с classом JsonConvert в Json.NET
  • Порядок сериализованных полей с использованием JSON.NET
  • Сериализация / десериализация пользовательской коллекции с дополнительными свойствами с помощью Json.Net
  • Строка Parse Json в C #
  • Что такое эквивалент JSON.NET XPath, SelectNodes XML, SelectSingleNode?
  • Удаление десериализации полиморфных classов json без информации о типе с использованием json.net
  • Уничтожить stream массива json по одному элементу за раз
  • Как игнорировать свойство в classе, если null, используя json.net
  • Настройте JSON.NET для игнорирования атрибутов DataContract / DataMember
  • Использование пользовательской десериализации тела WCF без изменения десериализации шаблона URI
  • Json.Net: Html Помощник не регенерирует
  • Давайте будем гением компьютера.