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:
- 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. - 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
Is the Use of Dynamic Considered a Bad Practice
Why Are Unsigned Int's Not Cls Compliant
Accessing Password Protected Network Drives in Windows in C#
Value of Type 'T' Cannot Be Converted To
No Overflow Exception for Int in C#
C# "Parameter Is Not Valid." Creating New Bitmap
Does C# Optimize the Concatenation of String Literals
How to Parse Hex Values into a Uint
Read from Location on Console C#
Why Must I Provide Explicitly Generic Parameter Types While the Compiler Should Infer the Type
Usercontrol' Constructor with Parameters in C#
Is It Safe to Check Floating Point Values for Equality to 0
Getting File Names Without Extensions
Test If a Property Is Available on a Dynamic Variable