1

I know that Json.NET supports conditional serialization using ShouldSerialize{PropName}

But is there any way to prevent an entire type to be serialized w/o changing the type that references it? e.g.

 public class Foo
 {
     public bool Enabled {get;set;}
     ...other properties
 }

 public class Bar
 {
     public Foo SomeFoo {get;set;}
     public Foo OtherFoo {get;set;}
 }

I want the Bar type to not include SomeFooo or OtherFoo depending on if the Enabled property is set. if SomeFoo.Enabled = false, then Bar.SomeFoo should not be serialized.

So I want a conditional serialization for a referencing property. And I don't want the consume of the Foo type to have any extra code or attribs. it should all go in the Foo type.

I could add a ShouldSerializeSomeFoo in Bar.. but that is not what I'm looking for..

2 Answers 2

2

You could write a custom JsonConverter to handle the serialization of Foo.

I've written a very basic version below, I'd suggest looking into it in a bit more depth though.

This version keeps the property reference, just doesn't serialize the object. You could also write a converter for Bar, which ignores the entire property.

public class FooJsonConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var foo = value as Foo;
        if (foo == null || !foo.Enabled)
            return;

        writer.WriteStartObject();

        writer.WritePropertyName("Enabled");
        serializer.Serialize(writer, foo.Enabled);

        //Write the rest of the serialization

        writer.WriteEndObject();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return serializer.Deserialize(reader, objectType);
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof (Foo);
    }
}

Usage:

var trueFoo = new Foo()
{
    Enabled = true
};

var falseFoo = new Foo()
{
    Enabled = false
};

var bar = new Bar()
{
    SomeFoo = trueFoo,
    OtherFoo = falseFoo
};


//{"SomeFoo":{"Enabled":true},"OtherFoo":null}
var json = JsonConvert.SerializeObject(bar, new FooJsonConverter());
Sign up to request clarification or add additional context in comments.

Comments

2

I think the best solution for this problem is to write a custom IContractResolver. The resolver can apply a ShouldSerialize method programmatically to each object containing a Foo, which will in turn inspect the Foo instance to see if it is enabled. If it is not, then that property will not be serialized at all.

The easiest way to create the resolver is to derive it from DefaultContractResolver and then override the CreateProperties method. Here is the code you would need:

using System;
using System.Collections.Generic;
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

class CustomResolver : DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
        foreach (JsonProperty prop in properties)
        {
            if (prop.PropertyType == typeof(Foo))
            {
                prop.ShouldSerialize = obj => 
                {
                    Foo foo = (Foo)type.GetProperty(prop.PropertyName).GetValue(obj);
                    return foo != null && foo.Enabled;
                };
            }
        }
        return properties;
    }
}

You can apply the custom resolver via JsonSerializerSettings like this:

JsonSerializerSettings settings = new JsonSerializerSettings
{
    ContractResolver = new CustomResolver(),
};
string json = JsonConvert.SerializeObject(objToSerialize, settings);

Here is a fiddle with a full demo: https://dotnetfiddle.net/wnLbyD

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.