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;
}
}