0

I have an issue when trying to map a JSON response I get from an API into an appropriate object that I made. Following is the JSON example

{
    "Count": "1",
    "Data": {
        "EmployeeMstr": {
            "ledger": "GL",
            "faid": "_tag_"
        }
    }
}

I need to create and object so that i can deserialize the above Json. I can create an object and desiarilse using JsonConvert.DeserializeObject<ResponseObject>(jsonResponse). Where ResponseObject is the class I created like following.

public class ResponseObject 
    {
        public string Count { get; set; }
        public string NextUri { get; set; }
        public Data Data{ get; set; }        
    }
public class Data
    {
        public string EmployeeMstr { get; set; }
    }

But the issue with this is, the key name "EmployeeMstr" in the above Json can be anything depending upon which table it is coming from ( like "HrNewHire" ,"Payroll" etc). I don't want to create separate object for all seperated tables. So what could be the best approach so that I can use this class to serialize the JSON irrespective of what that table name is?

Psth
  • 250
  • 1
  • 2
  • 11
  • You could use a generic, or use `dynamic`, or use an `ExpandoObject`. – dbc Mar 09 '20 at 23:05
  • or [deserialize to a Dictionary instead of a class](https://stackoverflow.com/questions/1207731/). – Dour High Arch Mar 09 '20 at 23:08
  • If you are looking to break out of strongly typed objects, I agree with @DourHighArch that breaking them into a dictionary is probably the cleaner option vs. expando objects/json overrides. – R. StackUser Mar 09 '20 at 23:33

3 Answers3

2

You could use a Dictionary to store the key values where the Key names could change. For example,

public class Value
{
    public string ledger { get; set; }
    public string faid { get; set; }
}

public class ResponseObject 
{
    public string Count { get; set; }
    public Dictionary<string,Value> Data { get; set; }  // Change here
    public string NextUri { get; set; }
}

Sample Output

enter image description here

Anu Viswan
  • 17,797
  • 2
  • 22
  • 51
0

You could implement a Json Converter:

This maps the variant properties to the property you want to set.

public class CustomFieldConverter : JsonConverter
{
    private readonly Dictionary<string, string> _propertyMappings = new Dictionary<string, string>
    {
        {"EmployeeMstr", "CustomProperty"},
        {"HrNewHire", "CustomProperty"},
        {"Payroll", "CustomProperty"}
    };

    public override bool CanWrite => false;

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType.GetTypeInfo().IsClass;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        object instance = Activator.CreateInstance(objectType);
        var props = objectType.GetTypeInfo().DeclaredProperties.ToList();

        JObject jo = JObject.Load(reader);
        foreach (JProperty jp in jo.Properties())
        {
            if (!_propertyMappings.TryGetValue(jp.Name, out var name))
                name = jp.Name;

            PropertyInfo prop = props.FirstOrDefault(pi =>
                pi.CanWrite && pi.GetCustomAttribute<JsonPropertyAttribute>().PropertyName == name);

            prop?.SetValue(instance, jp.Value.ToObject(prop.PropertyType, serializer));
        }

        return instance;
    }
}

You have to set the attribute in the Class where your custom property its.

[JsonConverter(typeof(CustomFieldConverter))]
public class Data

you can see a detailed example here:

https://www.jerriepelser.com/blog/deserialize-different-json-object-same-class/

You can use JObject as type of CustomProperty to allow to maps distinct json objects. But I think your code will remain something unintelligible.

Other way is to maps this property to a class with this structure:

public class CustomProperty
{
    [JsonProperty("TableName")]
    public string TableName{ get; set; }

    [JsonProperty("Data")]
    public Dictionary<string, object> Properties { get; set; }
}

An loads the properties in a dictionary with a JsonConverter

svladimirrc
  • 216
  • 1
  • 6
0

just replace your Model to dynamic JsonConvert.DeserializeObject<dynamic>(jsonResponse)

Ryan Motal
  • 362
  • 3
  • 15