0

We had a legacy WCF product which serializing POCO using XML Serialization attributes.

Here is a sample of the List, with XmlArray/XmlArrayItem attributes. Bit like [How do I Set XmlArrayItem Element name for a List<Custom> implementation?

[XmlArray("Things", Order = 4), XmlArrayItem("Thing")]
public List<Thing> Things { get; set; }

This produces XML response:

<m:Things>
  <m:Thing>
  ...
  </m:Thing>
  <m:Thing>
  ...
  </m:Thing>
  <m:Thing>
  ...
  </m:Thing>
</m:Things>

And also (via a external translation) converts to this Json response (plural named object with an inner array (singular named) Json response):

"Things": {
"Thing": [
    {
        ...
    },
    {
        ...
    }
]}

Now, we have a .NET Core 2.1 app with no XML output - only Json. So I want to serialize the List into this Json response so that I don't break any clients that are expecting this response.

I realize I could write a wrapper around the List but I have about 40 of these Lists to do, and calling code will get very murky. I fact if I do a Paste Special > Paste JSON as classes, it looks like:

  class Model
  {
     public ThingsWrapper Things { get; set; }
  }

    public class ThingsWrapper
    {
        public Thing[] Thing { get; set; }
    }

    public class Thing
    {
...
    }

called with var x = Things.Thing; // (yuck)

based on https://dotnetfiddle.net/vUQKV1 - I have tried this JsonConverter. However it comes out as this, which is around the other way. I need things as a object and thing as an array.

{
  "things": [
    {
      "thing": {
        "Id": 1
      }
    },
    {
      "thing": {
        "Id": 2
      }
    }
  ]
}
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

public class Program
{
    public static void Main()
    {
        var foo = new Foo();
        foo.Things = new List<Foo.Thing>{new Foo.Thing{Id = 1}, new Foo.Thing{Id = 2}};
        Console.WriteLine(JsonConvert.SerializeObject(foo, Formatting.Indented));
    }
}

class Foo
{
    [JsonProperty("things")]
    [JsonConverter(typeof(CustomArrayConverter<Thing>), "thing")]
    public List<Thing> Things
    {
        get;
        set;
    }

    public class Thing
    {
        public int Id
        {
            get;
            set;
        }
    }
}

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;
    }
}
2
  • You can use a custom JsonConverter -- although CustomCreationConverter will not work. The problem is that the name of the inner property "Thing" will differ for each list property, right? It's currently controlled by [XmlArrayItem(string name)] but the name passed to the constructor will differ from property to property, how do you intend to retain that name? Are you going to keep decorating your properties with XmlArrayItem attributes? Commented Dec 17, 2019 at 17:09
  • The Thing inner property will be only set once (It is an array of Thing). See code sample 2 above. It is not how I would have chosen to output the json.. but it is just what I have to work with. Any examples of how to use a JsonConverter? Commented Dec 17, 2019 at 21:41

1 Answer 1

2

Thanks to @Brian on Name array elements in Json.NET? https://dotnetfiddle.net/vUQKV1, which pointed me in the right direction.

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;
            JObject jObject = new JObject(new JProperty(PropertyName, new JArray(items.Select(i => JToken.FromObject(i, serializer)))));
            jObject.WriteTo(writer);
        }

        public override bool CanConvert(Type objectType)
        {
            // CanConvert is not called when the [JsonConverter] attribute is used
            return false;
        }
    }
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks yes I did

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.