Reputation: 1001
I'm looking to combine [JsonProperty("name")]
and ![JsonIgnore]
into my own custom resolver and I just need some help on the syntax.
So when serializing this class I want to ignore all properties without my custom attribute and also specify the serialized name for the property like so:
public class MyClass
{
[MyCustomProperty("name")]
public string SomeName { get; set; }
[MyCustomProperty("value")]
public string SomeValue { get; set; }
public string AnotherName {get; set; }
public string AnotherValue {get; set; }
}
Expected result:
{
"name": "Apple",
"value": "Delicious"
}
This is how far I got with my resolver:
public class MyCustomProperty : Attribute
{
public string Property { get; set; }
public MyCustomProperty(string property)
{
Property = property;
}
}
public class CustomResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
Type itemType = property.PropertyType.GetGenericArguments().First();
MyCustomProperty customProperty = itemType.GetCustomAttribute<MyCustomProperty>();
property.PropertyName = MyCustomProperty.Property;
return property;
}
}
I'm not exactly sure where to add the ignore if no attribute part.
Upvotes: 1
Views: 4625
Reputation: 129787
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
Upvotes: 1