parse.com: SerializationException десериализация объектов JSON со свойством __type

Я разрабатываю приложение UWP для Windows 10 и не могу избавиться от этой ошибки: «Исключение типа System.Runtime.Serialization.SerializationException произошло в mscorlib.ni.dll, но не было обработано в пользовательском коде».

Я использую Rest API для извлечения значений из хранилища данных в Parse и создания экземпляров объектов. Вот как выглядит мой класс

public class ImageTest
{
    public class Image
    {
        public string __type { get; set; }
        public string name { get; set; }
        public string url { get; set; }
    }

    public class Result
    {
        public string createdAt { get; set; }
        public Image image { get; set; }
        public string name { get; set; }
        public string objectId { get; set; }
        public string updatedAt { get; set; }
    }

    public class RootObject
    {
        public List<Result> results { get; set; }
    }
}

Вот как выглядит мой вывод JSON:

{
"results": [
    {
        "createdAt": "2015-11-16T02:04:17.403Z",
        "image": {
            "__type": "File",
            "name": "stark.jpg",
            "url": "http://xyz.parse.com/stark.jpg"
        },
        "name": "Stark",
        "objectId": "2ypGrvkvg0",
        "updatedAt": "2015-11-16T02:04:23.121Z"
    },
    {
        "createdAt": "2015-11-16T02:04:31.409Z",
        "image": {
            "__type": "File",
            "name": "targaryen.jpg",
            "url": "http://xyz.parse.com/targaryen.jpg"
        },
        "name": "Targaryen",
        "objectId": "otgO3scX3k",
        "updatedAt": "2015-11-16T02:04:40.094Z"
    }
]
}

Подробности сообщения об ошибке следующие: Дополнительная информация: Элемент ':image' содержит данные контракта данных ':File'. Десериализатор не знает ни одного типа, который сопоставляется с этим контрактом. Добавьте тип, соответствующий File, в список известных типов, например, используя атрибут KnownTypeAttribute или добавив его в список известных типов, передаваемых DataContractSerializer.


person Jason Bourne    schedule 16.11.2015    source источник


Ответы (1)


Ваша проблема в том, что вы используете DataContractJsonSerializer для десериализации JSON, а "__type" является зарезервированным свойством для этого сериализатора. Он используется для идентификации производных типов полиморфных типов. Из документов:

Сохранение информации о типе

Чтобы сохранить идентичность типа, при сериализации сложных типов в JSON можно добавить «подсказку типа», а десериализатор распознает подсказку и действует соответствующим образом. «Подсказка типа» — это пара «ключ-значение» JSON с именем ключа «__type» (два символа подчеркивания, за которыми следует слово «type»). Значение представляет собой строку JSON в форме "DataContractName:DataContractNamespace" (все, что находится до первого двоеточия, является именем)...

Подсказка типа очень похожа на атрибут xsi:type, определенный стандартом экземпляра схемы XML и используемый при сериализации/десериализации XML.

Элементы данных с именем "__type" запрещены из-за потенциального конфликта с подсказкой типа.

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

Однако вы можете использовать обработку полиморфизма сериализатором для чтения и записи "__type" автоматически, определив иерархию классов информации об изображении, в которой ваш тип Image является подклассом ожидаемого типа. Давайте переименуем его в FileImage для ясности:

public class ImageTest
{
    [DataContract(Namespace = "")]
    [KnownType(typeof(FileImage))]
    public abstract class ImageBase
    {
    }

    [DataContract(Name = "File", Namespace = "")]
    public sealed class FileImage : ImageBase
    {
        [DataMember(Name = "name")]
        public string name { get; set; }
        [DataMember(Name = "url")]
        public string url { get; set; }
    }

    [DataContract(Namespace = "")]
    public class Result
    {
        [DataMember]
        public string createdAt { get; set; }

        [IgnoreDataMember]
        public FileImage image { get { return imageBase as FileImage; } set { imageBase = value; } }

        [DataMember(Name = "image")] // Need not be public if DataMember is applied.
        ImageBase imageBase { get; set; }

        [DataMember]
        public string name { get; set; }

        [DataMember]
        public string objectId { get; set; }

        [DataMember]
        public string updatedAt { get; set; }
    }

    public class RootObject
    {
        public List<Result> results { get; set; }
    }
}

Теперь все должно работать.

Если позже вы обнаружите, что сервер отправляет данные JSON с дополнительными значениями "__type" и данными свойств (например, встроенное изображение Base64), теперь вы можете легко изменить свою модель данных, чтобы добавить дополнительные подклассы в ImageBase.

person dbc    schedule 17.11.2015
comment
Большое спасибо, похоже, ошибка устранена, и теперь программа компилируется. Как получить доступ к членам класса Result и класса FileImage при привязке их как DataContext (в частности, имя и URL-адрес)? - person Jason Bourne; 17.11.2015
comment
@JasonBourne - свойство image все еще существует и общедоступно. Он приводит базовое свойство ImageBase к FileImage и возвращает его. Таким образом, вы должны быть в состоянии привязаться к этому. - person dbc; 17.11.2015