Ganesh
Ganesh

Reputation: 91

Deserialize different json property to same model property conditionally

Lets say I have the below json.

{
   "allitemscount":2,
   "allitems":[
        {"itemid":"1","itemname":"one"}, 
        {"itemid":"2","itemname":"two"}],
   "customitems":[
       {"itemid":"3","itemname":"three"}, 
       {"itemid":"4","itemname":"four"}]
}

and when deserializing this json, it should go to the below C# model.

public class response
{
  public int allitemscount;
  public List<item> items;
}

public class item
{
   public string itemid;
   public string itemname;
}

Question: How to switch between allitems and customitems based on a condition? For eg., if useAllitems is true, allitems from the json to be filled in items and if useCustomItems is true, customitems to be filled in items property. Please help on how to do this.

Using JsonProperty on public List<item> items is allowing to switch between either allitems, but is there a way to deserialize based on the above mentioned condition.

Upvotes: 2

Views: 866

Answers (2)

Abhilash Ravindran C K
Abhilash Ravindran C K

Reputation: 1856

You can deserialize above json by changing your response class as follows,

public class response{
      public int allitemscount;
      public List<item> allitems;
      public List<item> customitems;    
}

then use the following code,

var jsonData = "{\"allitemscount\":2,   \"allitems\":[{\"itemid\":\"1\",\"itemname\":\"one\"}, {\"itemid\":\"2\",\"itemname\":\"two\"}],\"customitems\":[{\"itemid\":\"3\",\"itemname\":\"three\"},{\"itemid\":\"4\",\"itemname\":\"four\"}]}";

var data = JsonConvert.DeserializeObject<response>(jsonData);
foreach(var str in data.allitems) {
          Console.WriteLine(str.itemid +'-'+str.itemname);
}
foreach(var str in data.customitems) {
          Console.WriteLine(str.itemid +'-'+str.itemname);
}

Upvotes: 0

arslanaybars
arslanaybars

Reputation: 1853

I made it with writing our own ItemConverter which inherited from JsonConverter,

Sample model json that I use in my trying:

{
  "allitemscount": 2,
  "UseCustomItems": true,
  "allitems": [
    {
      "itemid": "1",
      "itemname": "one"
    },
    {
      "itemid": "2",
      "itemname": "two"
    }
  ],
  "customitems": [
    {
      "itemid": "3",
      "itemname": "three"
    },
    {
      "itemid": "4",
      "itemname": "four"
    }
  ]
}

Console application's main method:

static void Main(string[] args)
{
    using (StreamReader r = new StreamReader(@"\model.json")) // json path
    {
        string json = r.ReadToEnd();

        var deserializedJson = JsonConvert.DeserializeObject<Result>(json, new ItemConverter());
    }
}

Models:

public class Result // main object
{
    [JsonProperty("allitemscount")]
    public long Allitemscount { get; set; }

    public bool UseCustomItems { get; set; }
}

public class ResultA : Result // CustomItems Model
{
    [JsonProperty("customitems")]
    private List<Item> Items { get; set; }
}

public class ResultB : Result // AllItems Model
{
    [JsonProperty("allitems")]
    private List<Item> Items { get; set; }
}

public class Item
{
    [JsonProperty("itemid")]
    public string Itemid { get; set; }

    [JsonProperty("itemname")]
    public string Itemname { get; set; }
}

And the ItemConverter that we used while deserializing to object:

internal class ItemConverter : JsonConverter
{
    private Type currentType;

    public override bool CanConvert(Type objectType)
    {
        return typeof(Item).IsAssignableFrom(objectType) || objectType == typeof(Result);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject item = JObject.Load(reader);
        if (item["UseCustomItems"] != null)
        {
            // save the type for later.
            switch (item["UseCustomItems"].Value<bool>())
            {
                case true:
                    currentType = typeof(ResultA);
                    return item.ToObject<ResultA>(); // return result as customitems result
                case false:
                    currentType = typeof(ResultB);
                    return item.ToObject<ResultB>(); // return result as allitems result
            }
            return item.ToObject<Result>();
        }

        // use the last type you read to serialise.
        return item.ToObject(currentType);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

The result should be like bellowing image enter image description here

I hope this solution help to you

Upvotes: 2

Related Questions