0

i want to change the json property name dynamically and serialize the object.

here is my json for two different entities

For customer

{
  "userName": "66666",
  "password": "test1234",  
  "customersList": [
    {
      "address": "Test Stree2",
      "customerNumber": "US01-000281",
      "city": ""

    }
  ]
}

For contact

{
  "userName": "66666",
  "password": "test1234",  
  "contactList": [
    {
      "address": "Test stree1",
      "contactNumber": "US01-000281",
      "city": ""

    }
  ]
}

and the model that is holding this data is as follows

public class URequest<T>
    {

        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
        public string userName { get; set; }

        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
        public string password { get; set; }    

       [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
        public IList<T> requestList { get; set; }

    }

in above code requestList could contain list of contacts or customer but while sending i want to change the requestList json property name to respective entity name i.e. for customer it will be customerList and for contact it will be contactList after serializing.

Hunt
  • 8,215
  • 28
  • 116
  • 256
  • 1
    A custom resolver may help you here , https://stackoverflow.com/questions/37917164/newtonsoft-json-dynamic-property-name – theUser Jun 08 '17 at 11:01
  • 1
    Your sample suggests that *customer* and *contact* are practically identical apart from labeling the identifier (customer-/contactNumber). Have you considered using a common entity and just add a type identifier? It would allow you to add more types ("lead", "superuser", etc.) without changing all your coding. – Filburt Jun 08 '17 at 11:04
  • i have other class members too , just to simplify the example i have considered very few class members in both the models – Hunt Jun 08 '17 at 11:08
  • Theoretically you could do it using the [`JsonConverter`](http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_JsonConverter.htm) class, though I like @Filburt suggestion lots more :) – Icepickle Jun 08 '17 at 11:09
  • yes we can use `JsonConveter` but how thats the question :) – Hunt Jun 08 '17 at 11:17
  • I still do not understand why you need to tie class members to the list name property if your model uses a generic `IList`. – Filburt Jun 08 '17 at 11:23
  • i need to serialize the object and sending it to the server as a json so that server can insert the records at their end – Hunt Jun 08 '17 at 11:42

2 Answers2

6

You can create a custom JsonConverter.

Using custom JsonConverter in order to alter the serialization of the portion of an object

Example

public class Customer
{
    public string Name { get; set; }
}

public class Client
{
    public string Name { get; set; }
}

public class URequest<T>
{

    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public string userName { get; set; }

    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public string password { get; set; }

    [JsonIgnore]
    public IList<T> requestList { get; set; }

}

public class URequestConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(URequest<T>));
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var objectType = value.GetType().GetGenericArguments()[0];
        URequest<T> typedValue = (URequest<T>) value;

        JObject containerObj = JObject.FromObject(value);

        containerObj.Add($"{objectType.Name.ToLower()}List", JToken.FromObject(typedValue.requestList));
        containerObj.WriteTo(writer);
    }

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

You can use it like this

    [TestMethod]
    public void TestMethod1()
    {
        URequest<Customer> request = new URequest<Customer>();
        request.password = "test";
        request.userName = "user";
        request.requestList = new List<Customer>();

        request.requestList.Add(new Customer() { Name = "customer" });

        JsonSerializerSettings settings = new JsonSerializerSettings();
        settings.Formatting = Formatting.Indented;
        settings.Converters.Add(new URequestConverter<Customer>());

        Console.WriteLine(JsonConvert.SerializeObject(request, settings));
    }
bartbje
  • 331
  • 1
  • 7
  • i am getting error at `GetGenericArguments()[0]` it says type does not contain a definition for ` GetGenericArguments` and no extention method accepting a first argument of type 'Type'` – Hunt Jun 09 '17 at 06:38
  • I have resolved an error using `GetGenericTypeDefinition` instead of `GetGenericArguments` , can tell us how we can handle plural words like instead of `Contact` i have 'Opportunity` so that needs to be `Opportunities` – Hunt Jun 09 '17 at 11:29
  • 1
    And the problem is it adds one more duplicate block `{"userName":"666666","password":"ABC","companyId":"US01","page":1,"type":null,"IdProperty":"Contact","requestList":[{"birthdate":"2017-06-09","city":"","contactId":0}],"Id":0,"contactsList":[{"birthdate":"2017-06-09","city":"","contactId":0}],"contactId":0}` – Hunt Jun 09 '17 at 12:01
  • @Hunt, containerObj.Remove removes the duplicate block. – Anish Oct 31 '17 at 14:44
4

using the ContentResolver i have solve the issue

here is the code

public class UserRequestResolver : DefaultContractResolver
{
    private string propertyName;

    public UserRequestResolver()
    {
    }
    public UserRequestResolver(string name)
    {
        propertyName = name;
    }
    public new static readonly UserRequestResolver Instance = new UserRequestResolver();

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);

        if (property.PropertyName == "requestList")
        {
            property.PropertyName = propertyName;              
        }
        return property;
     }
}

once can pass specific property name in the constructor.

JsonSerializerSettings settings = new JsonSerializerSettings();
            settings.ContractResolver = new UserRequestResolver("contactList");
Aaron Hudon
  • 5,280
  • 4
  • 53
  • 60
Hunt
  • 8,215
  • 28
  • 116
  • 256