1

I have the following JSON to POST to my Web API endpoint.

[
    {
        "name": "REGION",
        "value": ["MA", "SE", "SW"]
    }
]

The Web API endpoint is as follows

public class Parameter
{
    public string Name { get; set; }
    // Value can be string, string[], int, or int[]
    public dynamic Value { get; set; }
}

[Route("{chart}/data/")]
[HttpPost]
public IHttpActionResult GetData(string chart, IList<Parameter> parameters)
{
    // ... do stuff ...
}

Whenever value in the JSON is an array the deserialized parameter's Value is a JArray rather than an array of string, int, etc. However, if value is a simply a string or number then Value in the deserialized parameters is also a string or a number.

What gives? Why isn't the array in the JSON being deserialized into an array of the proper type?

Ryan Taylor
  • 8,740
  • 15
  • 65
  • 98
  • 1
    That is how the Json.Net was designed. Value is dynamic. the framework will choose the least common denominator. Without a strongly typed object to bind to the model wont know what to convert the data to. – Nkosi Dec 12 '18 at 22:58
  • This feels like an [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) with a bigger issue around the design. What is this ultimately going to be used for? Why would such varying data be sent to that action? – Nkosi Dec 12 '18 at 22:59
  • If you don't want `"value"` to be deserialized into `JObject` or `JArray`, you could manually convert to the conventional .Net types instead. See [How do I use JSON.NET to deserialize into nested/recursive Dictionary and List?](https://stackoverflow.com/q/5546142) and [JSON.net serializes a json array into a JArray when the destination is an object. How can I change that?](https://stackoverflow.com/q/38594282). In fact this may be a duplicate of one or both; agree? – dbc Dec 12 '18 at 23:05
  • @Nkosi The endpoint accepts one or more parameters. Each parameter's value may be an int or a string. Ultimately, these are used in a where clause in SQL query to return data. Originally each parameter could have a single value. This worked well for several years. Recently, requirements changed and each parameter may have multiple values (all of the same type). – Ryan Taylor Dec 13 '18 at 14:07

1 Answers1

1

This was my solution. It "corrects" for JArray by inspecting the Value type after deserialization and converting it to the appropriate string[].

public class Parameter
{
    public string Name { get; set; }
    public dynamic Value { get; set; }

    [OnDeserialized]
    public void OnDeSerialized(StreamingContext context)
    {
        Type type = this.Value.GetType();
        if (type == typeof(JArray)) 
        {
            var value = (this.Value as JArray).ToObject(typeof(string[]));
            this.Value = value;
        }
    }
}
Ryan Taylor
  • 8,740
  • 15
  • 65
  • 98