5

I'm struggling with conditionally serializing a property of an object that is a property of another object itself. Consider the following class structure:

public class Message
{
    public string Content { get; set; }
    public IEnumerable<Attachment> Attachments { get; set; }
}

public class Attachment
{
    public string Base64Content { get; set; }
    public string FileName { get; set; }
}

In some scenarios I want to serialize everything in the Message class, including all Attachment objects and its properties. This can be done by using a simple JsonConvert.SerializeObject(). If I always wanted to ignore the Base64Content property, I could just add a '[JsonIgnore]' attribute on that property. However, there are some scenarios in which I want the Base64Content serialized, and in others I don't.

I though about creating a custom ContractResolver that ignores the Attachments property of the Message object. But of course, this ignores the whole list of Attachment objects and not just the Base64Content property.

Is there a way of writing a ContractResolver class that lets me ignore the Base64Content property when serializing the Message object?

Froodooo
  • 177
  • 1
  • 9
  • Could you make new classes, with the same structure, and with [JsonIgnore] as needed? Then serialise your existing class if you want everything serialised **or** map to your new class and serialise it if you want just some fields serialised. – mjwills Aug 31 '17 at 10:32
  • @mjwills that could be a solution, but would introduce a lot of (near) duplicate classes for something I hope to solve in a cleaner way. – Froodooo Aug 31 '17 at 11:02
  • You might be able to adapt the answer from [Json.NET serialize by depth and attribute](https://stackoverflow.com/q/36159424/3744182). – dbc Aug 31 '17 at 20:27

1 Answers1

3

Just create a custom contract resolver which excludes the properties passed to it while serializing and pass the Base64Content property in it conditionally.

public class CustomPropertiesContractResolver : DefaultContractResolver
{
    private HashSet<string> _propertySet;

    public CustomPropertiesContractResolver(IEnumerable<string> propertyNames)
    {
        if (propertyNames != null)
        {
            _propertySet = new HashSet<string>(propertyNames, StringComparer.OrdinalIgnoreCase);
        }
    }

    protected override List<MemberInfo> GetSerializableMembers(Type objectType)
    {
        List<MemberInfo> serializableMembers = null;
        var allMembers = base.GetSerializableMembers(objectType);

        if (_propertySet != null && _propertySet.Count > 0)
        {
            serializableMembers = allMembers.Where(m => !_propertySet.Contains(m.Name)).ToList();
        }
        return serializableMembers != null && serializableMembers.Count > 0 ? serializableMembers : allMembers;
    }
}

use it like:

IEnumerable<string> properties = null;
if (condition)
{
    properties = new List<string> { "Base64Content" };
}

var settings = new JsonSerializerSettings()
{
    ContractResolver = new CustomPropertiesContractResolver(properties)
};
var serializedStr = JsonConvert.SerializeObject(messages, settings);
ctor
  • 805
  • 1
  • 10
  • 26