1

I'm sure this has been asked but I'm unable to find it maybe because I don't know what the terms of it would be. Let's say I have the following:

JSON

{
    "Field1": 1234,
    "Field2": 5678,
    "MoreData": {
        "Field3": 9012,
        "Field4": 3456
    },
   "Field5": "Test"
}

Class

public class Sample()
{
    public int Field1 { get; set; }
    public int Field2 { get; set; }
    public int Field3 { get; set; }
    public int Field4 { get; set; }
    public string Field5 { get; set; }
}

If I deserialize this Field1, Field2, and Field5 will be populated but is there a way to also get Field3 and Field4 populated in an easy way.

I don't want to have a public class MoreData for Field2 and Field3.

aybe
  • 15,516
  • 9
  • 57
  • 105
Chris Ward
  • 771
  • 1
  • 9
  • 23
  • Well, you can have an `internal` class then ? :) – aybe Jul 07 '20 at 01:46
  • @Aybe I'm not sure what you mean, I don't want another class I just want to map the "MoreData" fields to the properties of the Sample Class – Chris Ward Jul 07 '20 at 01:48
  • Problem is your question is really vague, you should explain what you're trying to achieve instead of asking how to solve X or Y. Obviously what you ask is possible but it seems really weird. – aybe Jul 07 '20 at 01:51
  • I thought it was pretty clear, well clear to me. I want to deserialize that JSON into that class. – Chris Ward Jul 07 '20 at 02:04
  • I found [this](https://stackoverflow.com/questions/40439290/custom-deserialization-using-json-net) and [this](https://stackoverflow.com/questions/8796618/how-can-i-change-property-names-when-serializing-with-json-net) questions that will help you figure this out – Artur Jul 07 '20 at 02:05
  • @Artur I think the first link might be what I need to do, the second link I tried I was hoping I could do [JsonProperty(PropertyName = "MoreData.Field3")] but that didn't work – Chris Ward Jul 07 '20 at 02:08
  • I thought that would not be possible, yeah. So the first link with a custom `JsonConverter` would be a solution. [Here](https://stackoverflow.com/questions/33088462/can-i-specify-a-path-in-an-attribute-to-map-a-property-in-my-class-to-a-child-pr) is one doing exactly what you tried – Artur Jul 07 '20 at 02:12

3 Answers3

1

If you are unable to change models then try this:

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

    public CustomContractResolver()
    {
        this.PropertyMappings = new Dictionary<string, string> 
        {
            {"Field3", "MoreData.Field3"},
            {"Field4", "MoreData.Field4"},
        };
    }

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

And use this like this:

var sample = JsonConvert.DeserializeObject<Sample>(json, new JsonSerializerSettings(){
        ContractResolver = new SampleContractResolver()
    });
Rithik Banerjee
  • 447
  • 4
  • 16
  • Thanks for the great tip and it saved my day - only one tiny error, the constructor name should be same as class SampleContractResolver. – Stevey Sep 25 '22 at 17:47
0

You can use the setter to set your Field3 and Field4 values.

public class Sample
{
    public int Field1 { get; set; }
    public int Field2 { get; set; }
    public int Field3 { get; set; }
    public int Field4 { get; set; }
    public string Field5 { get; set; }
    public dynamic MoreData {
        set { 
            Field3 = value.Field3; 
            Field4 = value.Field4; 
        } 
    }
}

When you deserialize your Json above, you'll get the values copied to Field3 and Field4 of the Sample class as well.

Removed the MoreData class as per your requirement. You can use dynamic type to look up the variables for the MoreData object.

Jawad
  • 11,028
  • 3
  • 24
  • 37
  • While this is an option the link @Artur posted in his last comment works perfectly. https://stackoverflow.com/questions/33088462/can-i-specify-a-path-in-an-attribute-to-map-a-property-in-my-class-to-a-child-pr – Chris Ward Jul 07 '20 at 03:08
  • I didnt see that link but yeah, JsonProperty is another way to go about it. I saw your note where you said JsonProperty didnt work so thought this solution would work as well. – Jawad Jul 07 '20 at 03:10
0

Thank you to @Artur for offering this link Can I specify a path in an attribute to map a property in my class to a child property in my JSON? this worked perfectly.

You will have to use NewtonJson and not Microsoft's System.Text.Json to get this to work.

Once you create the class from the link above you can do the following.

{
    "Field1": 1234,
    "Field2": 5678,
    "MoreData": {
        "Field3": 9012,
        "Field4": 3456
    },
   "Field5": "Test"
}

[JsonConverter(typeof(JsonPathConverter))]
public class Sample()
{
    public int Field1 { get; set; }
    public int Field2 { get; set; }
    [JsonProperty("MoreData.Field3")]
    public int Field3 { get; set; }
    [JsonProperty("MoreData.Field4")]
    public int Field4 { get; set; }
    public string Field5 { get; set; }
}
Chris Ward
  • 771
  • 1
  • 9
  • 23