3

Is there a way to configure Json.NET to not serialize properties which have an [Obsolete] attribute?

e.g.

public class Foo
{
    public int Id { get; set; }

    [Obsolete]
    public int Age { get; set; }
 }

 var foo = new Foo { Id = 123, Age = 23 };
 var json = JsonConvert.SerializeObject(foo);

In the above example, the json is {"Id":123,"Age":23}

I would like {"Id":123}

Matt Frear
  • 52,283
  • 12
  • 78
  • 86

3 Answers3

9

Yes, you can use a custom ContractResolver to exclude properties marked obsolete.
Here is the code you would need for the resolver:

public class ExcludeObsoletePropertiesResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty prop = base.CreateProperty(member, memberSerialization);
        if (prop.AttributeProvider.GetAttributes(true).OfType<ObsoleteAttribute>().Any())
        {
            prop.ShouldSerialize = obj => false;
        }
        return prop;
    }
}

Then use it like this:

var settings = new JsonSerializerSettings
{
    ContractResolver = new ExcludeObsoletePropertiesResolver()
};
var json = JsonConvert.SerializeObject(foo, settings);

Working demo here: https://dotnetfiddle.net/gIRCD4

Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
  • Nice. Thanks for the fiddle! – Matt Frear Jun 21 '19 at 17:48
  • Wouldn't it be better to override the method that collects the members to be serialized and filtering out the members there? `protected override List GetSerializableMembers(Type objectType) { var members = base.GetSerializableMembers(objectType); members.RemoveAll(m => m.IsDefined(typeof(ObsoleteAttribute), true)); return members; }` – Sindri Jóelsson Jan 29 '20 at 23:20
  • @SindriJóelsson Depends what you are trying to do I guess. If you want to be able to exclude the members while serializing, but still allow them to be deserialized into (which seems like it might be desirable for an `[Obsolete]` property), then you should not filter out the members, but instead set up the `ShouldSerialize` predicate as shown in my answer. If you want to exclude them both ways, then filtering them out is one way to do that. Another way is to set `Ignored = true` on the properties. – Brian Rogers Jan 30 '20 at 01:22
  • @BrianRogers, I realized that after posting my answer. When I was implementing this for my use case the obsolete members would throw exceptions when accessed or set. – Sindri Jóelsson Jan 31 '20 at 08:05
1

You can utilise conditional serialisation as documented here: https://www.newtonsoft.com/json/help/html/ConditionalProperties.htm

If you have control over the class and want to target specific properties you know upfront it would be easier to use the first mechanism, offering ShouldSerializeAge() method

But most probably it seems you need something generic in this case you can create a IContractResolver class that uses Reflection to check whether a given property has the Obselete attribute

Mohammad
  • 1,930
  • 1
  • 21
  • 31
0

Expanding on Brian Rogers' answer: It's a little bit simpler/faster to filter out the members to exclude in an override of GetSerializableMembers() method rather than the CreateProperty(MemberInfo member, MemberSerialization memberSerialization) which gets called for on each MemberInfo returned by GetSerializedMembers() to avoid unnecessary calls to the CreateProperty method which does a bunch of reflection and delegate creation.

public class ExcludeObsoletePropertiesResolver : DefaultContractResolver
{
    protected override List<MemberInfo> GetSerializableMembers(Type objectType)
    {
        var members =  base.GetSerializableMembers(objectType);
        members.RemoveAll(m => m.IsDefined(typeof(ObsoleteAttribute), true));
        return members;
    }
}

Usage:

var settings = new JsonSerializerSettings
{
    ContractResolver = new ExcludeObsoletePropertiesResolver()
};
var json = JsonConvert.SerializeObject(foo, settings);