Consider the following json and models:
{
"Reference": "Bay House 22",
"Appliances": [
{
"Reference": "Kitchen Appliance 1",
"ApplianceType": "0",
"NumberOfSlots": 4
},
{
"Reference": "Kitchen Appliance 2",
"ApplianceType": "1",
"Capacity": 1500
}
]
}
public class HouseModel
{
public String Reference { get; set; }
[JsonConverter(typeof(ApplianceModelConverter))]
public IEnumerable<IApplianceModel> Appliances { get; set; }
}
public interface IApplianceModel
{
String Reference { get; set; }
ApplianceType ApplianceType { get; set; } // this is an enum
}
public class ToasterModel : IApplianceModel
{
public String Reference { get; set; }
public ApplianceType ApplianceType { get; set; }
public Int32 NumberOfSlots { get; set; }
}
public class KettleModel : IApplianceModel
{
public String Reference { get; set; }
public ApplianceType ApplianceType { get; set; }
public Int32 Capacity { get; set; }
}
I'm trying to deserialize an IEnumerable which could be a Toaster
or a Kettle
, using a custom json converter. The idea here is that I can return a concrete type once I know what the ApplianceType is, by looking at the json. I've been following this stackoverflow post to try and get this to work, but without success.
Here is the converter code:
public abstract class JsonCreationConverter<T> : JsonConverter
{
protected abstract T Create(Type objectType, JObject jObject);
public override Boolean CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
public override Boolean CanWrite
{
get { return false; }
}
public override Object ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
{
// Load JObject from stream
JObject jObject = JObject.Load(reader);
// Create target object based on JObject
T target = Create(objectType, jObject);
// Populate the object properties
serializer.Populate(jObject.CreateReader(), target);
return target;
}
}
public class ApplianceModelConverter: JsonCreationConverter<IApplianceModel>
{
protected override IApplianceModel Create(Type objectType, JObject jObject)
{
if (jObject["applianceType "] == null)
{
throw new ArgumentException("Missing ApplianceType");
}
ApplianceType applianceType = jObject.Value<ApplianceType>();
switch (applianceType )
{
case ApplianceType.Kettle:
return new KettleModel();
case ApplianceType.Toaster:
return new ToasterModel();
default:
throw new InvalidEnumArgumentException("ApplianceType not supported");
}
}
}
Currently I get an exception thrown when this line is executed: JObject jObject = JObject.Load(reader);
in the JsonCreationConverter
Newtonsoft.Json.JsonReaderException: 'Error reading JObject from JsonReader. Current JsonReader item is not an object: StartArray. Path 'Appliances'
I guess that it's getting to the IEnumerable and just failing, what am I doing wrong here?