5

I'm using JsonConvert in my project in order to make a json string from my object, but something weird is happening, one of entities losses data in the process, which is weird because when I'm debugging, the entity has values, but for some reason it gets lost during the process.

I use the JsonConvert.SerializeObject method, and this is my entity which looses data:

[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; }
}

Now, when I Look at the json, and I see all of the property from the BaseEntityDTO class, but not the other properties of the class itself.

Any idea why, is there a problem with the entities or something like that?

dbc
  • 104,963
  • 20
  • 228
  • 340
Golan Kiviti
  • 3,895
  • 7
  • 38
  • 63
  • 1
    It would be easier to help you if you'd provide a short but complete program demonstrating the problem. See [mcve]. – Jon Skeet Mar 27 '16 at 18:19
  • How are you trying to De-Serialize it? – Aizen Mar 27 '16 at 18:25
  • @Aizen Does it matter? the json is wrong after the searialization. – Golan Kiviti Mar 27 '16 at 18:29
  • of course, What you have there is a Model of the Data. It does not do any operation of its own. You didn't think that the model is doing all do work now, do you? – Aizen Mar 27 '16 at 18:32
  • of course it doesnt, i mentioned that im using the JsonConvert.SerializeObject. I use it like this: string json = JsonConvert.SerializeObject(media); – Golan Kiviti Mar 27 '16 at 18:35
  • 1
    This question most certainly don't has a duplicate, at least not the one that is referred to above. It would be nice if someone who knows how to do this would remove the "marked as duplicate" tags. – JRB Jul 25 '17 at 03:58

1 Answers1

3

The problem is that the properties of your PidDTO and VidDTO types are not being serialized. This is happening because their base type BaseEntityDTO is marked with [DataContract], and data contract serialization is opt-in.

The solution is also to mark these derived types with [DataContract], then mark all members you wish to serialize with [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; }
}

But why should this be necessary? In theory, the presence of the 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

However, Json.NET does not respect the Inherited = false attribute of DataContractAttribute and interprets all derived types of a data contract type as having opt-in serialization, as is explained here

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

So you need to add those attributes after all.

Alternatively, if you are only using data contract attributes to set IsRequired = true, you could switch to using [JsonProperty(Required = Required.AllowNull)] instead:

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; }
}

This allows your derived types to continue to have opt-out serialization.

dbc
  • 104,963
  • 20
  • 228
  • 340