Exclude Property from Serialization via Custom Attribute (JSON.Net)

Exclude property from serialization via custom attribute (json.net)

You have a few options. I recommend you read the Json.Net documentation article on the subject before reading below.

The article presents two methods:

  1. Create a method that returns a bool value based on a naming convention that Json.Net will follow to determine whether or not to serialize the property.
  2. Create a custom contract resolver that ignores the property.

Of the two, I favor the latter. Skip attributes altogether -- only use them to ignore properties across all forms of serialization. Instead, create a custom contract resolver that ignores the property in question, and only use the contract resolver when you want to ignore the property, leaving other users of the class free to serialize the property or not at their own whim.

Edit To avoid link rot, I'm posting the code in question from the article

public class ShouldSerializeContractResolver : DefaultContractResolver
{
public new static readonly ShouldSerializeContractResolver Instance =
new ShouldSerializeContractResolver();

protected override JsonProperty CreateProperty( MemberInfo member,
MemberSerialization memberSerialization )
{
JsonProperty property = base.CreateProperty( member, memberSerialization );

if( property.DeclaringType == typeof(Employee) &&
property.PropertyName == "Manager" )
{
property.ShouldSerialize = instance =>
{
// replace this logic with your own, probably just
// return false;
Employee e = (Employee)instance;
return e.Manager != e;
};
}

return property;
}
}

How to exclude property from Json Serialization

If you are using Json.Net attribute [JsonIgnore] will simply ignore the field/property while serializing or deserialising.

public class Car
{
// included in JSON
public string Model { get; set; }
public DateTime Year { get; set; }
public List<string> Features { get; set; }

// ignored
[JsonIgnore]
public DateTime LastModified { get; set; }
}

Or you can use DataContract and DataMember attribute to selectively serialize/deserialize properties/fields.

[DataContract]
public class Computer
{
// included in JSON
[DataMember]
public string Name { get; set; }
[DataMember]
public decimal SalePrice { get; set; }

// ignored
public string Manufacture { get; set; }
public int StockCount { get; set; }
public decimal WholeSalePrice { get; set; }
public DateTime NextShipmentDate { get; set; }
}

Refer http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size for more details

Json.Net attribute to ignore all properties

If you mark your class with [JsonObject(MemberSerialization.Fields)], that will get you most of the way there. This attribute tells Json.Net that you want it to serialize all fields in a class, regardless of access modifiers, but not properties.

However, if you have any auto properties in your class (i.e. those declared with { get; set; }) then this attribute will cause the compiler-generated backing fields to be serialized as well, which you may not want. To suppress those, you will need to use a custom IContractResolver. You can create one by inheriting from the DefaultContractResolver and overriding the CreateProperty method. In that method, check whether the class has the [JsonObject(MemberSerialization.Fields)] attribute applied, and if so, check whether the member is a compiler-generated field. If it is, then set it to be ignored.

class CustomResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty prop = base.CreateProperty(member, memberSerialization);
JsonObjectAttribute attr = prop.DeclaringType.GetCustomAttribute<JsonObjectAttribute>();
if (attr != null && attr.MemberSerialization == MemberSerialization.Fields &&
member.GetCustomAttribute<CompilerGeneratedAttribute>() != null)
{
prop.Ignored = true;
}
return prop;
}
}

To use the resolver, you need to pass it to the SerializeObject method via the JsonSerializerSettings:

var settings = new JsonSerializerSettings
{
ContractResolver = new CustomResolver(),
Formatting = Formatting.Indented
};
string json = JsonConvert.SerializeObject(yourObject, settings);

Here is a proof of concept: https://dotnetfiddle.net/aNXWbn

Ignore some of the properties during Json.NET serializing but required on others

Try the below code

    [JsonProperty(PropertyName = "componentMainVersion", DefaultValueHandling = DefaultValueHandling.Include)] 
public ushort Version { get; set; }

Required is a different property which makes sure that value for the property is required always

Custom JSON contract resolver to ignore all properties without a custom annotation

JsonProperty has an AttributeProvider on it which you can use to find the custom attributes on that property. I recommend you use that. So basically you would try to get the attribute, and if it exists, you set the name like you are doing, otherwise you set Ignored = true.

As an aside, I would recommend you rename your MyCustomProperty class to MyCustomPropertyAttribute, in keeping with standard conventions for classes that derive from System.Attribute. (Don't worry, the [MyCustomProperty("name")] annotation need not change, as the Attribute part is optional in annotations.) You should also apply the [AttributeUsage] attribute to your custom attribute class to indicate how it is allowed to be used. Lastly, I recommend you rename Property to PropertyName to make it clear that it is a name (string) and not the property itself (e.g. PropertyInfo).

So the code would look like this:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class MyCustomPropertyAttribute : Attribute
{
public string PropertyName { get; set; }
public MyCustomPropertyAttribute(string propertyName)
{
PropertyName = propertyName;
}
}

public class CustomResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
MyCustomPropertyAttribute customAttribute = (MyCustomPropertyAttribute)property.AttributeProvider.GetAttributes(typeof(MyCustomPropertyAttribute), true).FirstOrDefault();
if (customAttribute != null)
{
property.PropertyName = customAttribute.PropertyName;
}
else
{
property.Ignored = true;
}
return property;
}
}

Working demo: https://dotnetfiddle.net/thQc0f


All of that said, you don't actually need a custom resolver to get the behavior you want. You could simply apply a [JsonObject(MemberSerialization.OptIn)] attribute to MyClass and then use the normal [JsonProperty] attributes on those properties that you want to be included. Any properties not marked will then be ignored. (See Serialization Attributes in the Json.Net documentation.)

[JsonObject(MemberSerialization.OptIn)]
public class MyClass
{
[JsonProperty("name")]
public string SomeName { get; set; }

[MyCustomProperty("value")]
public string SomeValue { get; set; }

public string AnotherName {get; set; }

public string AnotherValue {get; set; }
}

Demo: https://dotnetfiddle.net/qY6nGR



Related Topics



Leave a reply



Submit