Stringer Bell
Stringer Bell

Reputation: 265

Modify/Add property via custom IContractResolver

I have a class:

 public class MyClass
 {
    public MyEnum Foo{ get; set; }
 }

During serialization i'd like to change the output from

{
   "Foo": 1
}

to

{
   "Foo": "EnumName"
}

I've tried creating an IValueProvider but hit dead ends every way I go. (My scenario is a bit more complicated than stated; I need to find a way to do this entirely within the IContractResolver.)

Upvotes: 2

Views: 1411

Answers (1)

dbc
dbc

Reputation: 117036

You could create a custom ContractResolver inheriting from DefaultContractResolver that automatically applies StringEnumConverter to every contract for an enum or nullable enum:

public class StringEnumContractResolver : DefaultContractResolver
{
    readonly StringEnumConverter converter;

    public StringEnumContractResolver() : this(true, false) { }

    public StringEnumContractResolver(bool allowIntegerValue, bool camelCaseText)
    {
        this.converter = new StringEnumConverter { AllowIntegerValues = allowIntegerValue, CamelCaseText = camelCaseText };
    }

    protected override JsonPrimitiveContract CreatePrimitiveContract(Type objectType)
    {
        var contract = base.CreatePrimitiveContract(objectType);
        var type = Nullable.GetUnderlyingType(contract.UnderlyingType) ?? contract.UnderlyingType;
        if (type.IsEnum && contract.Converter == null)
            contract.Converter = converter;
        return contract;
    }
}

Notes:

  • If the enum type already has a JsonConverter applied, that is kept in preference to the default StringEnumConverter.

  • Adding the converter to the JsonPrimitiveContract for the enum itself, rather than to every JsonProperty for members that return the enum, ensures that the converter is applied to enums in collections and dictionaries.

  • The IValueProvider merely provides methods to get and set values and thus is less convenient to this purpose than the converter. You would need to perform a nested serialization and deserialization of the enum value as a JSON string inside it, but it isn't designed for this and so doesn't have access to the JSON reader, writer, or serializer. In addition, there is no value provider for dictionary values or collection items that are enums.

  • You may want to cache the contract resolver for best performance as explained here.

Sample .Net fiddle.

Upvotes: 2

Related Questions