2

we have our C# class as below

public class PrimaryContact
{
   public string PrefixTitle { get; set; }

   public string SurName { get; set; }

   public string GivenName { get; set; }
}

we need to serialise to the json object as

"primaryContact": {
      "prefixTitle": {
        "value": "mrs"
      },
      "surName": "abcd",
      "givenName": "abcd"      
    }

Please note the prefixTitle is intended with value. for some selected attributes we need to serialize like this. Also, we need to read from JSON and deserialise into the class. Is there any generic best approach we can follow by decorating the elements so that we can achieve this result?

dbc
  • 104,963
  • 20
  • 228
  • 340
Badri Prasad
  • 107
  • 1
  • 1
  • 9
  • Look into library Newtonsoft.Json like Newton.Json.JsonConvert.DeserializeObject this should help you out :) – sjdm Dec 12 '18 at 05:08
  • https://www.newtonsoft.com/json – sjdm Dec 12 '18 at 05:09
  • Hi sjdm, please see my requirement I need to serialize into a specific structure, not straightforward class to json serialisation. – Badri Prasad Dec 12 '18 at 05:29
  • You can use the JsonConvert.SerializeObject(); method to build your own json string however you like, have a look through the documentation to do this. The newtonsoft library goes both ways. – sjdm Dec 12 '18 at 05:36
  • Quick question: did you accept dbc answer after already accepting a different answer first? Thanks, I test something for a secret hat. – Shadow The GPT Wizard Dec 12 '18 at 13:58

4 Answers4

2

As you have tagged your question with , you can do this by applying a custom JsonConverter to the "selected attributes" that should be nested inside a {"value" : ... } object when serialized.

First, define the following converter:

public class NestedValueConverter<T> : JsonConverter
{
    class Value
    {
        public T value { get; set; }
    }

    public override bool CanConvert(Type objectType)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        switch (reader.MoveToContent().TokenType)
        {
            case JsonToken.Null:
                return null;

            default:
                return serializer.Deserialize<Value>(reader).value;
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, new Value { value = (T)value });
    }
}

public static partial class JsonExtensions
{
    public static JsonReader MoveToContent(this JsonReader reader)
    {
        if (reader.TokenType == JsonToken.None)
            reader.Read();
        while (reader.TokenType == JsonToken.Comment && reader.Read())
            ;
        return reader;
    }
}

Now, apply it the "selected attributes" of PrimaryContact as follows:

public class PrimaryContact
{
    [JsonConverter(typeof(NestedValueConverter<string>))]
    public string PrefixTitle { get; set; }

    public string SurName { get; set; }

    public string GivenName { get; set; }
}

And you will be able to deserialize and serialize as follows:

var settings = new JsonSerializerSettings
{
    ContractResolver = new CamelCasePropertyNamesContractResolver(),
};
var root = JsonConvert.DeserializeObject<RootObject>(jsonString, settings);

var json2 = JsonConvert.SerializeObject(root, Formatting.Indented, settings);

Notes:

Sample fiddle here.

dbc
  • 104,963
  • 20
  • 228
  • 340
  • 1
    Thanks for the perfect solution. this is what i was expecting. – Badri Prasad Dec 12 '18 at 06:45
  • If we have many varieties of intended attributes (like amount, code, value in the below example) then can we have a generic class to the server different types? { "risk": { "code": "reg" }, "rent": { "amount": 50000 }, "city": { "value": "A001" } } – Badri Prasad Dec 14 '18 at 05:03
  • @BadriPrasad - not information in your comment for me to say. You might want to ask a second question with your complete requirements. – dbc Dec 14 '18 at 06:13
1

Here Prefix Title Also a class not a string. Here your class want to look like this.

public class PrimaryContact
{
   public PrefixTitle prefixTitle{ get; set; }

   public string surName{ get; set; }

   public string givenName{ get; set; }
}

public class PrefixTitle {
   public string value {get; set;}
}

Install Newtonsoft.json libraby file to your project : -> Open Package manager console in Tools NuGet Package and paste it then hit enter.

Install-Package Newtonsoft.Json -Version 12.0.1

Convert a Class to Json :

string output = JsonConvert.SerializeObject(classname);

Convert a Json to Object :

Here object denotes a Class

Object output = JsonConvert.DeSerializeObject<object>(jsonString);

Here You can find optimized code you can use in your project directly :

public static string getJsonFromClass(object objectName){
    return JsonConvert.SerializeObject(object);
}

public static T getObjectFromJson<T>(string jsonString){
    T t = default(T);
    try{
       t = JsonConvert.DeSerializeObject<T>(classname);
    }catch(Exception e){
       Debug.WriteLine(e.Message);
    }
    return t;
}

You can use this Method to achieve your output by :

string jsonData = getJsonFromClass(Prefix);

string JsonString = "<here your json string>";

Prefix getObjectFromJson = getObjectFromJson<Prefix>(JsonString);

thats all ..

I hope this can help for you..

Mohideen Asraf
  • 32
  • 1
  • 1
  • 8
  • This also works for my requirement, but I have many attributes where I will receive as indeded value attributes. Instead of creating classes I would prefer to have an attribute level decoration method to solve the requirement. Anyhow thanks for the suggestions. – Badri Prasad Dec 12 '18 at 06:47
0

You can achieve this by changing your model like:

public class PrimaryContact
{
   public Prefix PrefixTitle  { get; set; }

   public string SurName { get; set; }

   public string GivenName { get; set; }
}

public class Prefix
{
   public string Value  { get; set; }
}

Then

Newton.Json.JsonConvert.DeserializeObject<PrimaryContact>();
Tarik Tutuncu
  • 790
  • 4
  • 12
0

You need to write a custom serializer for your object. Here is an example to show how you can do this with extending JsonConverter and using some custom attribute to determine if your object/property should wrapped:

[WrapperAttribute(Key = "primaryContact")]
public class PrimaryContact
{
    [WrapperAttribute(Key= "prefixTitle")]
    public string PrefixTitle { get; set; }

    public string SurName { get; set; }

    public string GivenName { get; set; }
}

public class WrapperAttribute : Attribute
{
    public string Key { get; set; }
}


public class WrapperSerializer : JsonConverter<PrimaryContact>
{
    public override void WriteJson(JsonWriter writer, PrimaryContact value, JsonSerializer serializer)
    {
        Type type = value.GetType();

        JObject root = new JObject();

        foreach (var property in type.GetAllProperties())
        {
            if (property.HasAttribute<WrapperAttribute>())
            {
                JProperty wrappedProperty = new JProperty(property.GetAttribute<WrapperAttribute>().Key);
                JObject wrappedChild = new JObject();
                wrappedProperty.Value = wrappedChild;

                JProperty wrappedChildProperty = new JProperty("value");
                wrappedChildProperty.Value = JToken.FromObject(property.GetValue(value));

                wrappedChild.Add(wrappedChildProperty);

                root.Add(wrappedProperty);
            }
            else
            {
                var childProperty = new JProperty(property.Name);

                childProperty.Value = JToken.FromObject(property.GetValue(value));
                root.Add(childProperty);
            }

        }

        if (type.HasAttribute<WrapperAttribute>())
        {
            JObject wrappedRoot = new JObject();
            var wrappedProperty = new JProperty(type.GetAttribute<WrapperAttribute>().Key);
            wrappedProperty.Value = root;
            wrappedRoot.Add(wrappedProperty);
            wrappedRoot.WriteTo(writer);
        }
        else
        {
            root.WriteTo(writer);
        }

    }

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

in main :

PrimaryContact contact = new PrimaryContact();
contact.GivenName = "test name";
contact.PrefixTitle = "test title";
contact.SurName = "test surname";

JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Converters.Add(new WrapperSerializer());

var serialized = JsonConvert.SerializeObject(contact, settings);

output :

{
    "primaryContact": {
        "prefixTitle": {
            "value": "test title"
        },
        "SurName": "test surname",
        "GivenName": "test name"
    }
}
Emre Savcı
  • 3,034
  • 2
  • 16
  • 25