Mike
Mike

Reputation: 6050

Turning specific object fields into Json

I have a nested object

public class CardListViewModel
{

    public virtual Guid Id { get; set; }


    public virtual IEnumerable<Card> CardList { get; set; }

}

public class Card
{       
    public virtual Guid Id { get; set; }

    public virtual string IndexName { get; set; }

    public virtual Image CardImage { get; set; }
}

public class Image
{
//... 
public virtual string Src { get; set; }
//...
}

So card may be

CardListViewModel.CardList[0] = {Id:5678, IndexName:"Visa", {Src:"Visa.png"}}
CardListViewModel.CardList[1] = {Id:5555, IndexName:"MasterCard", {Src:"MasterCard.png"}}

The result I want is a Json object like the following

{
    "Visa": "Visa.png",
    "MasterCard": "MasterCard.png"
}

I can't modify the POCO, all I want is a JSON fragment for each card in the list and their corresponding image. Of course I can brute force this with StringBuilder and loops, but I was wondering if there was a way to accomplish this with the JsonConvert library or any other good tools that handle the mapping for me?

Upvotes: 1

Views: 52

Answers (2)

dbc
dbc

Reputation: 116785

Given that I can't modify the POCO and you are looking to use , you can create a custom JsonConverter for objects of type IEnumerable<Card> as follows:

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;

public class CardListConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(IEnumerable<Card>).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var list = existingValue as ICollection<Card> ?? new List<Card>();
        var obj = JObject.Load(reader);
        foreach (var property in obj.Properties())
        {
            list.Add(new Card { IndexName = property.Name, CardImage = new Image { Src = (string)property.Value } });
        }
        return list;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var collection = (IEnumerable<Card>)value;
        writer.WriteStartObject();
        foreach (var item in collection)
        {
            writer.WritePropertyName(item.IndexName);
            writer.WriteValue(item.CardImage == null ? null : item.CardImage.Src);
        }
        writer.WriteEndObject();
    }
}

Then use it in serialization settings as follows:

var settings = new JsonSerializerSettings
{
    Converters = { new CardListConverter() },
};
var json = JsonConvert.SerializeObject(CardListViewModel, Formatting.Indented, settings);

And your CardListViewModel will be serialized as follows:

{
  "Id": "c2a7cc0f-0e6b-40a0-9020-aeba436265d4",
  "CardList": {
    "Visa": "Visa.png",
    "MasterCard": "MasterCard.png"
  }
}

Sample fiddle.

Upvotes: 0

Chris
Chris

Reputation: 322

I'd use LINQ to map it and NewtonsoftJson to build the JSON.

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Linq;

var mappedCards = JsonConvert.SerializeObject(new JObject (
  from card in CardListViewModel.CardList
  select new JProperty(card.IndexName, card.CardImage.Src)));

Upvotes: 2

Related Questions