1

I want to modify JSON.NET so that when I am serializing a Model from my API it sends only an array of IDs for a composite Collection object.

For example:

class Employee 
{
    public ICollection<Address> Addresses { get; set; }
}

class Address 
{
    public int id;
    public string location;
    public string postcode;
}

Then when I send that back through WebApi

Request.Createresponse(HttpStatusCode.OK, new Employee());

Instead of this:

{
    "Addresses" : 
    [
        {"id" : 1, "location" : "XX", "postcode" : "XX" },
        {"id" : 2, "location" : "XX", "postcode" : "XX" }
    ]
}

It just sends as this:

{
    "Addresss" : [1,2]
}

I want this to be happening application-wide and I don't want to modify at the specific place.

How can I achieve this using the JSON.NET serializer?

Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
codebased
  • 6,945
  • 9
  • 50
  • 84

2 Answers2

4

You can get the result you want using a custom JsonConverter such as this:

class IdOnlyListConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (typeof(IEnumerable).IsAssignableFrom(objectType) && 
                objectType != typeof(string));
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        JArray array = new JArray();
        foreach (object item in (IEnumerable)value)
        {
            PropertyInfo idProp = item.GetType().GetProperty("id");
            if (idProp != null && idProp.CanRead)
            {
                array.Add(JToken.FromObject(idProp.GetValue(item, null)));
            }
        }
        array.WriteTo(writer);
    }

    public override bool CanRead
    {
        get { return false; }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

In your model, wherever you have a collection of something where you only want the IDs, decorate the collection property with a [JsonConverter] attribute specifying the custom converter. For example:

class Employee
{
    public string name { get; set; }

    [JsonConverter(typeof(IdOnlyListConverter))]
    public ICollection<Address> Addresses { get; set; }
}

class Address
{
    public int id { get; set; }
    public string location { get; set; }
    public string postcode { get; set; }
}

When the collection gets serialized, the converter will be used, and only the ID values will be written out. Demo:

class Program
{
    static void Main(string[] args)
    {
        Employee emp = new Employee
        {
            name = "Joe",
            Addresses = new List<Address>
            {
                new Address { id = 1, location = "foo", postcode = "bar" },
                new Address { id = 2, location = "baz", postcode = "quux" }
            }
        };

        string json = JsonConvert.SerializeObject(emp);
        Console.WriteLine(json);
    }
}

Output:

{"name":"Joe","Addresses":[1,2]}
Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
0

Please have a look at Json.Net's documentation.

public class Address
{
    [JsonProperty("Id")]
    public int I'd { get; set; }

    [JsonIgnore]
    public string Location { get; set; }

    [JsonIgnore]
    public string PostalCode { get; set; }
}

The only drawback to this is that you'll never be able to serialize the Location and PostalCode properties to JSON should you ever want to.

I believe there is a way to specify the serialization that should be used when serializing to JSON with Json.Net. Again, have a look at their documentation.

fourpastmidnight
  • 4,032
  • 1
  • 35
  • 48
  • That is fair to know, but I don't want to use ignore as you have said the impact. I just want this behaviour only if address is being used as composite variable – codebased Jul 27 '14 at 09:45
  • I have asked this question to json.net forum however is someone out here that can explain me if they are using some other serializer. I am trying to use Api that is going to be used by ember. – codebased Jul 27 '14 at 10:45
  • @codebased Ember is a client-side tool while Json.Net is server side. You should have no issues with ember.js. I'll try to post a more "flexible" example in a little while if no one beats me to it. – fourpastmidnight Jul 27 '14 at 14:33
  • I don't think I am talking about client-server. I will check with Brian answer what he has to offer. – codebased Jul 27 '14 at 22:39
  • @BrianRogers answer is the one you want. `JsonConverter` is what I was thinking of. I just couldn't remember it at the time. – fourpastmidnight Jul 27 '14 at 22:45