3

I need to serialize only first level of an object by JsonConvert.SerializeObject. I've tried MaxDepth = 1, but this property is only for Deserialization.

Desired behaviour (Property Bar is missing or is null):

class Foo
{
    public int First { get; set; } = 123;
    public string Second { get; set; } = "smurf";
    public DateTime Third { get; set; } = DateTime.Now;
    public Bar Bar { get; set; } = new Bar { Fourth = 999 };

}

class Bar
{
    public int Fourth { get; set; }
}

void Test(){
    var foo = new Foo();
    var jsonResult = JsonConvert.SerializeObject(foo);

    // jsonResult: 
    // {
    //    "First": 123,
    //    "Second": "smurf",
    //    "Third": "6.4. 2020 7:16",
    // }
}

How should I setup JsonConvert.SerializeObject to ignore children non-primitive objects in serialization? Many thanks.

Lopuch
  • 664
  • 2
  • 5
  • 20
  • 1
    You could create a custom JsonConverter. That way you have full control over what's getting serialized. [Example](https://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm) – Volkmar Rigo Apr 06 '20 at 05:25
  • Json.NET is a contract-based serializer which creates a contract for each type to be serialized, then serializes according to the contract. You basically want a different contract depending on depth, which it isn't designed to do. See [Json.NET serialize by depth and attribute](https://stackoverflow.com/q/36159424/3744182) for one possible approach. – dbc Apr 06 '20 at 05:29

1 Answers1

1

I found a solution.

I made a custom JsonConverter:

    public class OnlyPrimitiveJsonConverter : JsonConverter
    {
        private readonly Type[] _types;

        public OnlyPrimitiveJsonConverter(params Type[] types)
        {
            _types = types;
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            JToken t = JToken.FromObject(value, new JsonSerializer()
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore
            });

            if (t.Type != JTokenType.Object)
            {
                t.WriteTo(writer);
            }
            else
            {
                JObject o = (JObject)t;

                var propertiesToRemove = new List<string>();

                foreach (var prop in value.GetType().GetProperties())
                {
                    if (
                        !prop.PropertyType.IsPrimitive &&
                        !prop.PropertyType.IsValueType &&
                        prop.PropertyType != typeof(string)
                        )
                    {
                        propertiesToRemove.Add(prop.Name);
                    }
                }

                foreach (var propToRemove in propertiesToRemove)
                {
                    o.Remove(propToRemove);
                }

                o.WriteTo(writer);
            }
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
        }

        public override bool CanRead
        {
            get { return false; }
        }

        public override bool CanConvert(Type objectType)
        {
            return _types.Any(t => t == objectType);
        }
    }

I do not declare its flawlessness but it works for me. It simply removes non primitive and non valuetypes.

Lopuch
  • 664
  • 2
  • 5
  • 20