2

My problem is quite simple.. What I would like to do is this:

[JsonConverter(typeof(MyConverter)] object SomeProperty {get;set;} 

But be able to write it as a custom attribute so I simply can decorate my properties with a pre-defined JsonConverter attribute.. so for instance

[MyCustomConverter] object SomeProperty {get;set;} 

Would in this case be treated as [JsonConverter(typeof(MyConverter))]

Any ideas?

Br, Inx

2 Answers 2

1

It's not trivial, but you can do this if you implement a custom IContractResolver that takes your attributes into account.

There are several steps involved in doing this:

  1. Create an abstract base class for your attributes that extends System.Attribute:

    public abstract class ConverterAttribute : Attribute { public abstract JsonConverter Converter { get; } } 
  2. Next, you need to create the IContractResolver that will actually use your attribute1:

    public class CustomAttributeContractResolver : DefaultContractResolver { protected override JsonObjectContract CreateObjectContract(Type objectType) { JsonObjectContract contract = base.CreateObjectContract(objectType); IEnumerable<JsonProperty> withoutConverter = contract.Properties.Where( pr => pr.MemberConverter == null && pr.Converter == null); // Go over the results of calling the default implementation. // check properties without converters for your custom attribute // and pull the custom converter out of that attribute. foreach (JsonProperty property in withoutConverter) { PropertyInfo info = objectType.GetProperty(property.UnderlyingName); var converterAttribute = info.GetCustomAttribute<ConverterAttribute>(); if (converterAttribute != null) { property.Converter = converterAttribute.Converter; property.MemberConverter = converterAttribute.Converter; } } return contract; } } 
  3. Create the attribute that overrrides ConverterAttribute.Converter, returning your custom converter:

    public class MyCustomConverterAttribute : ConverterAttribute { get { return new MyCustomConverter(); } } 
  4. Decorate your class with the attribute:

    public class MyClass { [MyCustomConverter] public object MyProperty { get; set; } } 
  5. When serializing or deserializing, specify the contract resolver in the JsonSerializerSettings you use:

    var settings = new JsonSerializerSettings(); settings.ContractResolver = new CustomAttributeContractResolver(); string serialized = JsonConverter.SerializeObject(new MyClass()); 

I'd say that this probably isn't worth the small benefit--all you're really doing is saving a few characters, unless your attribute does something else.


1: I'm not sure what the difference between MemberConverter and Converter. When serializing, only the Converter property was needed, but deserializing required MemberConverter. I'll keep digging, but hopefully someone can provide some insight. Looks like others have had this same question as well.

Sign up to request clarification or add additional context in comments.

2 Comments

Hi! It seams like even if i decorate my property with [MyCustomConverter].. the withoutConverter-object within the CustomAttributeContractResolver still picks up the decorated property..
Its supposed to -- withoutConverter holds properties without a JsonConverter attribute. It should pick up the property and then use the attribute's underlying Converter.
0

It does not appear to be possible. The JsonConverterAttribute and TypeConverterAttribute classes are both sealed, and these are the classes used by Json.NET to supply a custom type converter.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.