Сериализация с JsonConvert теряет данные

Я использую JsonConvert в своем проекте, чтобы сделать строку json из моего объекта, но происходит что-то странное, одна из сущностей теряет данные в процессе, что странно, потому что, когда я отлаживаю, у сущности есть значения, но по какой-то причине он теряется в процессе.

Я использую метод JsonConvert.SerializeObject, и это моя сущность, которая теряет данные:

[DataContract]
public class MediaDTO : BaseEntityDTO
{
    [DataMember(IsRequired = true)]
    public int Id { get; set; }

    [DataMember(IsRequired = true)]
    public bool IsAlive { get; set; }

    [DataMember(IsRequired = true)]
    public string Description { get; set; }

    [DataMember(IsRequired = true)]
    public PidDTO Pid { get; set; }
}

[DataContract]
public class BaseEntityDTO
{ 
    [DataMember(IsRequired = true)]
    public bool IsDeleted { get; set; }

    [DataMember(IsRequired = true)]
    public DateTime AddedDate { get; set; }

    [DataMember(IsRequired = true)]
    public DateTime UpdatedDate { get; set; }
}

public class PidDTO : BaseEntityDTO
{
    public string PidId { get; set; }
    public VidDTO Vid { get; set; }
    public string Name { get; set; }
    public virtual bool IsFromUser { get; set; }
}

public VidDTO : BaseEntityDTO
{
    public virtual string VidId { get; set; }
    public virtual string Name { get; set; }
    public virtual bool IsFromUser { get; set; }
}

Теперь, когда я смотрю на json, я вижу все свойства класса BaseEntityDTO, но не другие свойства самого класса.

Любая идея, почему, есть проблема с сущностями или что-то в этом роде?


person Golan Kiviti    schedule 27.03.2016    source источник
comment
Было бы легче помочь вам, если бы вы предоставили короткую, но полную программу, демонстрирующую проблему. См. минимально воспроизводимый пример.   -  person Jon Skeet    schedule 27.03.2016
comment
Как вы пытаетесь десериализовать его?   -  person Aizen    schedule 27.03.2016
comment
@Айзен Это имеет значение? json неверен после сериализации.   -  person Golan Kiviti    schedule 27.03.2016
comment
конечно, у вас есть модель данных. Он не выполняет никаких операций самостоятельно. Вы же не думали, что сейчас модель делает всю работу, не так ли?   -  person Aizen    schedule 27.03.2016
comment
конечно, нет, я упомянул, что использую JsonConvert.SerializeObject. Я использую это так: string json = JsonConvert.SerializeObject(media);   -  person Golan Kiviti    schedule 27.03.2016
comment
У этого вопроса наверняка нет дубликата, по крайней мере, не тот, о котором говорилось выше. Было бы неплохо, если бы кто-то, кто знает, как это сделать, удалил бы помеченные как дубликаты теги.   -  person JRB    schedule 25.07.2017


Ответы (1)


Проблема заключается в том, что свойства ваших типов PidDTO и VidDTO не сериализуются. Это происходит потому, что их базовый тип BaseEntityDTO помечен [DataContract], а сериализация контрактов данных необязательна.

Решение также состоит в том, чтобы пометить эти производные типы с помощью [DataContract], а затем пометить все члены, которые вы хотите сериализовать, с помощью [DataMember]:

[DataContract]
public class PidDTO : BaseEntityDTO
{
    [DataMember]
    public string PidId { get; set; }
    [DataMember]
    public VidDTO Vid { get; set; }
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public virtual bool IsFromUser { get; set; }
}

[DataContract]
public class VidDTO : BaseEntityDTO
{
    [DataMember]
    public virtual string VidId { get; set; }
    [DataMember]
    public virtual string Name { get; set; }
    [DataMember]
    public virtual bool IsFromUser { get; set; }
}

Но зачем это должно быть необходимо? Теоретически наличие атрибута DataContractAttribute, примененный к базовому классу, не должен влиять на производные типы, поскольку DataContractAttribute устанавливает AttributeUsageAttribute.Inherited = false:

[AttributeUsageAttribute(AttributeTargets.Class|AttributeTargets.Struct|AttributeTargets.Enum, Inherited = false, 
AllowMultiple = false)]
public sealed class DataContractAttribute : Attribute

Однако Json.NET не учитывает атрибут Inherited = false для DataContractAttribute и интерпретирует все производные типы типа контракта данных как имеющие независимую сериализацию, как объясняется здесь

[Json.NET] обнаруживает DataContractAttribute в базовом классе и предполагает независимую сериализацию.

Таким образом, вам нужно добавить эти атрибуты в конце концов.

В качестве альтернативы, если вы используете атрибуты контракта данных только для установки IsRequired = true можно переключиться на использование [JsonProperty(Required = Required.AllowNull)] вместо этого:

public class MediaDTO : BaseEntityDTO
{
    [JsonProperty(Required = Required.AllowNull)]
    public int Id { get; set; }

    [JsonProperty(Required = Required.AllowNull)]
    public bool IsAlive { get; set; }

    [JsonProperty(Required = Required.AllowNull)]
    public string Description { get; set; }

    [JsonProperty(Required = Required.AllowNull)]
    public PidDTO Pid { get; set; }
}

public class BaseEntityDTO
{
    [JsonProperty(Required = Required.AllowNull)]
    public bool IsDeleted { get; set; }

    [JsonProperty(Required = Required.AllowNull)]
    public DateTime AddedDate { get; set; }

    [JsonProperty(Required = Required.AllowNull)]
    public DateTime UpdatedDate { get; set; }
}

Это позволяет вашим производным типам продолжать сериализацию отказа.

person dbc    schedule 27.03.2016