0

I wanted to add [JsonProperty("")] dynamically , how can I achieve this?

class Address
{
     public string Number { get; set; }
     public string Street { get; set; }
     public string City { get; set; }
     public string Country { get; set; }
}

class Person
{
     public string Name { get; set; }
     public int Age { get; set; }
     public Address PostalAddress { get; set; }
}

F.e I wanted to add [JsonProperty("")] annotation to nested class at runtime.

 class Address
    {    [JsonProperty("Nmb")]
         public string Number { get; set; }
          [JsonProperty("Str")]
         public string Street { get; set; }
         public string City { get; set; }
         public string Country { get; set; }
    }

I need to add dynamically because the class I use is coming from other library. My target aim is getting serialized json with shortened attribute names. How can I do this?

ozziem
  • 155
  • 3
  • 12
  • Then write a new class with fitting naming for serialization and map this class to your new class. – Ralf Sep 16 '22 at 11:02
  • I have too much nested classes , so I can not apply this: https://stackoverflow.com/questions/73718309/how-to-add-mapper-to-javascriptserializer-serialize-to-get-customminified-js/73721449?noredirect=1#comment130201912_73721449 – ozziem Sep 16 '22 at 11:04
  • If you think so. Having different models for different purposes is a pretty standard thing in most architectures. Its natural to apply it here. The library needs it for its workings(for whatever) and you need something for serialization. Two different duties therefore two different models. – Ralf Sep 16 '22 at 11:07

2 Answers2

1

You can use Newtonsoft.Json.Serialization's ContractResolver for this purpose, define all the property-to-property mapping for json that needs to be serialized or de-serialized. Sample:

public class CustomContractResolver : DefaultContractResolver
{
    private Dictionary<string, string> PropertyMappings { get; set; }

    public CustomContractResolver()
    {
        this.PropertyMappings = new Dictionary<string, string>
        {
            {"Number", "Nmb"},
            {"Street", "Str"},
            //all properties,
        };
    }

    protected override string ResolvePropertyName(string propertyName)
    {
        string resolvedName = null;
        var resolved = this.PropertyMappings.TryGetValue(propertyName, out resolvedName);
        return (resolved) ? resolvedName : base.ResolvePropertyName(propertyName);
    }
}

Here is how to use it:

var jsonObject = JsonConvert.DeserializeObject(jsonString, new JsonSerializerSettings{ ContractResolver = new CustomContractResolver() });
Rithik Banerjee
  • 447
  • 4
  • 16
  • Thanks but I want to get json with shortened names so I want to add annotations. This is deserialize one, I want to serialize and get the shortened names at json . Does it work with that purpose? – ozziem Sep 16 '22 at 10:57
  • `var jsonString = JsonConvert.SerializeObject(jsonObject, new JsonSerializerSettings{ ContractResolver = new CustomContractResolver() });` – Rithik Banerjee Sep 16 '22 at 11:00
  • thanks so much , but one more question, how it will work for nested classes? What would happen if I have same attribute name at other classes? I just wanted to change one attribute name in one nested class. (It is in 3 rd nested layer) Will this code work? – ozziem Sep 16 '22 at 11:02
  • `{"Address.Street", "Adr.Str"},` Hope this helps you. – Rithik Banerjee Sep 16 '22 at 11:04
  • `{"Model_Class_Name.Model_Property_Name.Model_Child_Property_Name", "JSON_Parent_Name.JSON_Property_Name.JSON_Child_Property_Name"},` – Rithik Banerjee Sep 16 '22 at 11:08
  • so for nested ones f.ex if Address includes one more nested class named ClassX, and classX has attribute YYY ; {"Address.ClassX.YYY ", Address.ClassX.Y} will work? and I think you can not shortened {"Address.Street", "Adr.Str"}, like this should be {"Address.Street", "Address.Str"}, ? – ozziem Sep 16 '22 at 11:09
  • you are correct. it should work. – Rithik Banerjee Sep 16 '22 at 11:10
  • {"Address.Street", "Adr.Str"}, like this should be {"Address.Street", "Address.Str"}, ? – ozziem Sep 16 '22 at 11:11
  • {"C#ModelName.Str", "JsonNodeName.Str"} – Rithik Banerjee Sep 16 '22 at 11:14
  • what is the point of changing class names? Because class names wont be in json after serialization? – ozziem Sep 16 '22 at 11:21
  • its for nested json node class name – Rithik Banerjee Sep 16 '22 at 11:43
  • I mean when you serialize json, Class names are not extracted. so why did you shorten Address class? I cant get it. {"Name":xxx,"Age":yyy,","PostalAddress ":{"Nmb":xxx, "Str":yyy, .City: "zzz", ............. } } – ozziem Sep 16 '22 at 12:51
  • EDİT: I applied your method, it is working, perfect. but still if we have same atttribute name for nested classes, it would be problem as we can not write class name like {"Address.Street", "Address.Str"} .. I tried this but it can not find proper way, nested class not working... I am still trying – ozziem Sep 16 '22 at 16:05
  • {"Address.Street", "Address.Str"} is not working... so this answer is just for unnested class, for nested class it is not working – ozziem Sep 17 '22 at 14:06
0

For my question, there is no proper method to add annotations at runtime. But to serialize json, if we need customSerialization, like the answer posted above , we can do stg like this: (The above answer wont be proper for nested class to me, if we identify class names, we need to use this way)

https://stackoverflow.com/a/33290710/1133217

Also this way prevents from creating unneccesary objects for serializing by using

 public static readonly CustomDataContractResolver Instance = new CustomDataContractResolver ();

When user clicks first time , it will be created, when browser is open , even other request come , it wont be created twice. Plus this way we can identify class names, and guarantte which attribute will change in which class.

ozziem
  • 155
  • 3
  • 12