How to omit an inherited property from JSON.NET Serialization

If I have the following classes, I want to serialize using JSON.NET:

[DataContract]
public class Thing
{
    [DataMember(Name = "@context")]
    public string Context => "http://schema.org"
}

[DataContract]
public class Organization : Thing
{
    [DataMember(Name = "address")]
    public Address Address { get; set; }

    ...
}

[DataContract]
public class Address : Thing
{
    ...
}

When I use JSON.NET to serialize the organization, I get:

{
  "@context": "http://schema.org",
  "address": {
    "@context": "http://schema.org",
    ...
  }
  ...
}

What is the most efficient way to ensure that a property is @contextdisplayed only at the top level Organization, and not in the object Address?

+4
source share
2 answers

If Organization- the only descendant of the top level Thing, and also type fields Organizationcannot appear in serialized objects, you can easily do this by specifying ShouldSerializeContextin the Thingfollowing way:

[DataContract]
public class Thing
{
    [DataMember(Name = "@context")]
    public string Context => "http://schema.org";
    public bool ShouldSerializeContext() { return this is Organization; }
}

: https://dotnetfiddle.net/GjmfbA


- Thing , . WriteJson . Context , writer.Path, :

[DataContract]
[JsonConverter(typeof(NoContextConverter))]
public class Thing
{
    [DataMember(Name = "@context")]
    public string Context => "http://schema.org";
}

// ...............

public class NoContextConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var props = value.GetType().GetProperties()
            .Where(p => Attribute.IsDefined(p, typeof(DataMemberAttribute)))
            .ToList();
        if (writer.Path != "")
            props.RemoveAll(p => p.Name == "Context");

        writer.WriteStartObject();
        foreach (var prop in props)
        {
            writer.WritePropertyName(prop.GetCustomAttribute<DataMemberAttribute>().Name);
            serializer.Serialize(writer, prop.GetValue(value, null));
        }
        writer.WriteEndObject();
    }

    public override bool CanConvert(Type objectType)
    {
        return typeof(Thing).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

: https://dotnetfiddle.net/cIlXID

N.B. - dotnetfiddle.net DataContractAttribute DataMemberAttribute System.Runtime.Serialization, .

+2

@DimitryEgorov , , , , . StringBuilder JSON.

private const string ContextPropertyJson = "\"@context\":\"http://schema.org\",";

public override string ToString() => RemoveAllButFirstContext(
    JsonConvert.SerializeObject(this, new JsonSerializerSettings));

private static string RemoveAllButFirstContext(string json)
{
    var stringBuilder = new StringBuilder(json);
    var startIndex = ContextPropertyJson.Length + 1;
    stringBuilder.Replace(
        ContextPropertyJson, 
        string.Empty, 
        startIndex, 
        stringBuilder.Length - startIndex - 1);
    return stringBuilder.ToString();
}
0

Source: https://habr.com/ru/post/1678860/


All Articles