使用 JsonConvert 进行序列化会丢失数据

Serialization with JsonConvert Loses Data

我在我的项目中使用 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 class 中的所有 属性,但没有看到 class本身。

知道为什么吗,是实体有问题还是类似问题?

问题 是您的 PidDTOVidDTO 类型的属性没有被序列化。发生这种情况是因为它们的基本类型 BaseEntityDTO 标记为 [DataContract],并且数据契约序列化是 opt-in

解决方法也是将这些派生类型标记为[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 applied to the base class should not affect your derived types, because DataContractAttribute sets AttributeUsageAttribute.Inherited = false:

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

但是,Json.NET 不尊重 DataContractAttributeInherited = false 属性,并将数据合同类型的所有派生类型解释为具有选择加入序列化,如解释的那样 here

[Json.NET] detects the DataContractAttribute on the base class and assumes opt-in serialization.

所以你毕竟需要添加那些属性。

或者,如果您仅使用数据协定属性来设置 IsRequired = true, you could switch to using [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; }
}

这允许您的派生类型继续选择退出序列化。