2
votes

I am using JSON.NET to serialize a class to JSON. The class contains a property which consists of a list of items, and I want to serialize the items themselves in a custom way (by dynamically including only certain properties, using a customized ContractResolver). So basically I want to serialize the parent class itself in a standard way, with the DefaultContractResolver, but serialize this one property in a custom way, with my own ContractResolver.

JSON.NET has methods that probably allow this but the documentation is rather sketchy. Any help would be appreciated.

2

2 Answers

2
votes

I solved this problem with a ContractResolver. The list of objects that I want to serialize is heterogeneous, so I have to pass it two arguments, a list of properties to be serialized, and a list of types to which the property list applies. So it looks like this:

    public class DynamicContractResolver : DefaultContractResolver
    {
        private List<string> mPropertiesToSerialize = null;
        private List<string> mItemTypeNames = new List<string>();

        public DynamicContractResolver( List<string> propertiesToSerialize,
            List<string> itemTypeNames )
        {
            this.mPropertiesToSerialize = propertiesToSerialize;
            this.mItemTypeNames = itemTypeNames;
        }

        protected override IList<JsonProperty> CreateProperties( Type type, MemberSerialization memberSerialization )
        {
            IList<JsonProperty> properties = base.CreateProperties( type, memberSerialization );
            if( this.mItemTypeNames.Contains( type.Name ) )
                properties = properties.Where( p => mPropertiesToSerialize.Contains( p.PropertyName ) ).ToList();
            return properties;
        }
    }

And it is called like this:

            DynamicContractResolver contractResolver = new DynamicContractResolver( propsToSerialize, GetItemTypeNames() );
            json = JsonConvert.SerializeObject( this, Formatting.None,
                new JsonSerializerSettings { ContractResolver = contractResolver } );

where GetItemTypeNames() calls GetType().Name on each of the items in the list that I want to serialize and writes them distinctly to a list.

Sorry my original question was vague and badly phrased, and if somebody has a better solution I am certainly not wedded to this one.

0
votes

Here's a version that's a bit better. It associates type names with properties, so you can specify which properties you wish to have serialized at every level. The keys to the dictionary are type names; the value is a list of properties to be serialized for each type.

class PropertyContractResolver : DefaultContractResolver
{
    public PropertyContractResolver( Dictionary<string, IEnumerable<string>> propsByType )  
    {
        PropertiesByType = propsByType;
    }

    protected override IList<JsonProperty> CreateProperties( Type type, MemberSerialization memberSerialization )
    {
        IList<JsonProperty> properties = base.CreateProperties( type, memberSerialization );
        if( this.PropertiesByType.ContainsKey( type.Name ) )
        {
            IEnumerable<string> propsToSerialize = this.PropertiesByType[ type.Name ];
            properties = properties.Where( p => propsToSerialize.Contains( p.PropertyName ) ).ToList();
        }
        return properties;
    }

    private Dictionary<string, IEnumerable<string>> PropertiesByType
    {
        get;
        set;
    }

}