Search code examples
c#asp.net-web-apijson.netasp.net-web-api2jsonserializer

How to pass multiple arguments to a JsonConverter when applied via an attribute?


We are having a web api project and inorder to convert the date time to date and vice versa, we are using DateTimeconverter extended from JsonConverter. We are using this in the form of an attribute for all the required DateTime properties (as shown below):

[JsonConverter(typeof(CustomDateConverter))]

The CustomDateConverter is as below:

public class CustomDateConverter: JsonConverter
{
    private string[] formats = new string[] { "yyyy-MM-dd", "MM/dd/yy", "MM/dd/yyyy", "dd-MMM-yy" };
    
    public CustomDateConverter(params string[] dateFormats)
    {
        this.formats = dateFormats;
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(DateTime);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // custom code
    }
    
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // custom code
    }
}

As you can see, the converter's constructor has a variable number of params string arguments, corresponding to all acceptable DateTime formats. My question is how can I apply such a converter using JsonConverterAttribute?


Solution

  • You can use the [JsonConverterAttribute(Type,Object[])] attribute constructor to pass arguments to your CustomDateConverter when it is constructed by Json.NET. This constructor automatically sets the ConverterParameters property:

    public class RootObject
    {
        [JsonConverter(typeof(CustomDateConverter), new object [] { new string [] { "dd-MMM-yy", "yyyy-MM-dd", "MM/dd/yy", "MM/dd/yyyy" } } )]
        public DateTime DateTime { get; set; }
    }
    

    Note that the use of params in the JsonConverterAttribute constructor and in your constructor might lead one to think that the correct syntax is

    [JsonConverter(typeof(CustomDateConverter), new object [] { "dd-MMM-yy", "yyyy-MM-dd", "MM/dd/yy", "MM/dd/yyyy" } )]
    

    Or even

    [JsonConverter(typeof(CustomDateConverter),"dd-MMM-yy", "yyyy-MM-dd", "MM/dd/yy", "MM/dd/yyyy")]
    

    However, these will not work. params is really just compile-time syntax sugar that tells the compiler to compile code with a variable number of arguments at the end of a method call into a single argument whose value is an array containing the arguments. As such it has no no impact on invocation by reflection. Since Json.NET looks for a constructor with the appropriate signature using the reflection method Type.GetConstructor(Type []), the presence of params is irrelevant: your constructor's reflected signature has one single parameter, namely an array of strings, so that is what must be supplied for the converter parameters. The syntaxes that do not work correspond to a constructor with four string arguments.

    fiddle.