0

Using Json.NET 10.0.3. Consider the following sample:

class Foo
{
   [JsonProperty("ids")]
   public int[] MyIds { get; set; }
}

Obviously, the elements of the array are unnamed. Now consider the following json:

{
  "ids": [{
      "id": 1
    }, {
      "id": 2
    }
  ]
}

And then we try to parse it:

var json = @"{""ids"":[{""id"":1},{""id"":2}]}";
var result = JsonConvert.DeserializeObject<Foo>(son);

Parsing the above fails with the following message:

Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: {. Path 'ids', line 1, position 9.

I know I can wrap int in a class and name it "id" there, but I'm wondering if this can be done without this extra work. The reason being what appears to be a limitation in SQL Server 2016. See this question.

l33t
  • 18,692
  • 16
  • 103
  • 180
  • Obvious thing to do would be to use a [custom `JsonConverter`](https://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm). – dbc Jan 13 '18 at 20:21
  • But with a custome converter your C# wouldn't match your JS. I suppose it depends on where you want to lie. – H H Jan 13 '18 at 20:33
  • @HenkHolterman Not sure if `""` is that much better than `\"`. – l33t Jan 13 '18 at 20:36

1 Answers1

2

You can make a custom JsonConverter to translate between the two array formats:

class CustomArrayConverter<T> : JsonConverter
{
    string PropertyName { get; set; }

    public CustomArrayConverter(string propertyName)
    {
        PropertyName = propertyName;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JArray array = new JArray(JArray.Load(reader).Select(jo => jo[PropertyName]));
        return array.ToObject(objectType, serializer);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        IEnumerable<T> items = (IEnumerable<T>)value;
        JArray array = new JArray(
            items.Select(i => new JObject(
                new JProperty(PropertyName, JToken.FromObject(i, serializer)))
            )
        );
        array.WriteTo(writer);
    }

    public override bool CanConvert(Type objectType)
    {
        // CanConvert is not called when the [JsonConverter] attribute is used
        return false;
    }
}

To use the converter, mark your array property with a [JsonConverter] attribute as shown below. Note the type parameter for the converter must match the item type of the array, and the second parameter of the attribute must be the property name to use for the values in the JSON array.

class Foo
{
    [JsonProperty("ids")]
    [JsonConverter(typeof(CustomArrayConverter<int>), "id")]
    public int[] MyIds { get; set; }
}

Here is a round-trip demo: https://dotnetfiddle.net/vUQKV1

Brian Rogers
  • 125,747
  • 31
  • 299
  • 300