1

Am using Netonsoft.Json and ASP.Net Web API.

I have to generate a json string as below,

"view":
[
{"id": "MAIN_TOP_IMAGE_b", 
    "image":
    {
        "value": "Base64 encoding(image.jpg)",
        "type": "jpg;base64",
        "align": "right"
    }
},
{"id": "MAIN_BARCODE_a", 
    "barcode":
    {
        "value": " 32455232453",
        "type": "QRCODE",
        "caption": "1432343fdoadkfe"
    }
}
]

I have created a classes as below,

public class View
{   
    [JsonProperty("id")]
    public string Id { get; set; }
    public Object ElementData { get; set; }
}

public class Image
{
    [JsonProperty("value")]
    public string Value { get; set; }

    [JsonProperty("type")]
    public string Type { get; set; }

    [JsonProperty("align")]
    public string Align { get; set; }

    [JsonProperty("bgcolor")]
    public string BGColor { get; set; }
}

public class Text
{
    [JsonProperty("value")]
    public string Value { get; set; }

    [JsonProperty("color")]
    public string Color { get; set; }

    [JsonProperty("align")]
    public string Align { get; set; }
}

public class Barcode
{
    [JsonProperty("value")]
    public string Value { get; set; }

    [JsonProperty("type")]
    public string Type { get; set; }

    [JsonProperty("caption")]
    public string Caption { get; set; }
}

Whereas ElementData will be having one of the objects (Image, Barcode, Text) The elementdata property name should use its type.

Is there any way to do this?

ekad
  • 14,436
  • 26
  • 44
  • 46
SVP
  • 43
  • 1
  • 4

3 Answers3

1

You can create a custom Json converter to do whatever you want, how ever you want. Just like described here.

In the write method just check the type of your object, and serialize it accordingly.

Community
  • 1
  • 1
OVi
  • 21
  • 6
0

You might be able to get what you want with inheritance...

public abstract class View
{   
    public string Id { get; set; }
}

public class ImageView : View
{
    public Image Image { get; set; }
}

public class BarcodeView : View
{
    public Barcode Barcode { get; set; }
}

public class TextView : View
{
    public Text Text { get; set; }
}

According to this article, you just need to configure the Json.net serializer with the proper type name handing and it should work...

// WebApiConfig.cs

var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Objects;

// use camelCase resolver to do away with the JsonProperty annotations
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

You would need a root object that has a View property that's a list of Views...

public class RootObject 
{
    public List<View> View { get; set; }
}
Anthony Chu
  • 37,170
  • 10
  • 81
  • 71
  • Not quite. `TypeNameHandling = TypeNameHandling.Objects` causes the serializer to output an additional property of the name `$type` for every object in the JSON hierarchy. It will not change the name of an existing property based on its type, which is what was asked for in the question. – Brian Rogers Feb 13 '14 at 18:12
0

You can solve this by making a custom JsonConverter for your View class like this:

class ViewConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(View));
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        View view = (View)value;
        JObject jo = new JObject();
        jo.Add("id", view.Id);
        if (view.ElementData != null)
        {
            jo.Add(view.ElementData.GetType().Name.ToLower(),
                   JObject.FromObject(view.ElementData));
        }
        jo.WriteTo(writer);
    }

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

Then decorate your View class with a [JsonConverter] attribute like this:

[JsonConverter(typeof(ViewConverter))]
public class View
{
    [JsonProperty("id")]
    public string Id { get; set; }
    public Object ElementData { get; set; }
}

Your example is missing a container class to hold the list of views, so I am assuming it looks like this:

public class RootObject
{
    [JsonProperty("view")]
    public List<View> Views { get; set; }
}

With all these pieces in place, you can serialize the RootObject to get the JSON that you want:

class Program
{
    static void Main(string[] args)
    {
        RootObject obj = new RootObject();
        obj.Views = new List<View>
        {
            new View
            {
                Id = "MAIN_TOP_IMAGE_b",
                ElementData = new Image
                {
                    Value = "Base64 encoding(image.jpg)",
                    Type = "jpg;base64",
                    Align = "right"
                }
            },
            new View
            {
                Id = "MAIN_BARCODE_a",
                ElementData = new Barcode
                {
                    Value = " 32455232453",
                    Type = "QRCODE",
                    Caption = "1432343fdoadkfe"
                }
            }
        };

        string json = JsonConvert.SerializeObject(obj, Formatting.Indented);
        Console.WriteLine(json);
    }
}

Output:

{
  "view": [
    {
      "id": "MAIN_TOP_IMAGE_b",
      "image": {
        "value": "Base64 encoding(image.jpg)",
        "type": "jpg;base64",
        "align": "right",
        "bgcolor": null
      }
    },
    {
      "id": "MAIN_BARCODE_a",
      "barcode": {
        "value": " 32455232453",
        "type": "QRCODE",
        "caption": "1432343fdoadkfe"
      }
    }
  ]
}
Brian Rogers
  • 125,747
  • 31
  • 299
  • 300