0

I am getting JSON objects through http requests and I was wondering if there is a way to access, via Newtonsoft to child properties of an object directly.

This is an example of the JSON I receive:


{
  "id": "005",
  "name": "John",
  "job": 
    {
      "id":"110",
      "name":"developer",
    }
}

And I would like to get just the job id without mapping the whole object into a class.

[JsonProperty("id")]
public string id { get; set; }

[JsonProperty("name")]
public string Name {get; set; }

[JsonProperty("job.id")] //Doesn't seems to work, heh :)
public string JobId { get; set; }

Is there a simple way to do something like this without making a new class neither add extra logic to the code?

I'm looking for a way that allows me to do it directly in the constructor, so that later I can deserialize it to an object in the following way:

var myObject = JsonConvert.DeserializeObject<MyObject>(response);
Aritzbn
  • 174
  • 3
  • 18
  • @Nikolay It seems a too complex solution for the type of project in which it will be implemented, anyway it was just what I was looking for. – Aritzbn Mar 16 '23 at 08:49
  • *Is there a simple way to do something like this **without making a new class** neither add extra logic to the code?* -- basically no. You need either a `Job` class, a DTO class, or a custom converter class like the ones from [Can I specify a path in an attribute to map a property in my class to a child property in my JSON?](https://stackoverflow.com/q/33088462/3744182) that @Nikolay linked to. – dbc Mar 16 '23 at 17:30

4 Answers4

0

Yes you can achieve it using SelectToken()

var jObject = JObject.Parse(jsonString);
var jobId = (string)jObject.SelectToken("job.id");

or simply with GetValue()

var jobId = (string)jObject.GetValue("job")["id"];
AVTUNEY
  • 923
  • 6
  • 11
  • Could I implement this in the property of a class and not through code? – Aritzbn Mar 16 '23 at 08:35
  • @Aritzbn Your question asked how to do it _without_ mapping it to a class, didnt it? – Jamiec Mar 16 '23 at 09:01
  • I think it was not difficult to deduce that I did not want to add "additional logic" to the code either, your answer was valid, indeed, but it is not what I am looking for, I have modified the question to be clearer, sorry. – Aritzbn Mar 16 '23 at 09:16
0

How about accessing using the indexer:

JObject o = JObject.Parse(json);
var info = o["job"]["name"].ToString();
Marc Wittmann
  • 2,286
  • 2
  • 28
  • 41
  • Could I implement this in the property of a class and not through code? This is not what I'm looking for. – Aritzbn Mar 16 '23 at 08:35
  • You don`t want to create a model class. This won't need a model. You can also write this as an extension method to the JObject class. Apart from that I don't understand what your restrictions are here – Marc Wittmann Mar 16 '23 at 09:00
0

If you don't want to create a new class for sub element job, try dynamic type for that property.

[JsonProperty("id")]
public string id { get; set; }

[JsonProperty("name")]
public string Name {get; set; }

[JsonProperty("job")] //Name as per response
public dynamic Job { get; set; }

You can even use dynamic type to deserialize whole json, if you don't want any class to be created.

var myObject = JsonConvert.DeserializeObject<dynamic>(response);

Only concern while using dynamic type is, we need to carefully handle/unbox while using those properties and its values, or else we got run time error.

Bhuvaneshwaran
  • 192
  • 1
  • 2
  • 10
  • The use of `dynamic` has a high impact on performance and I personally tend to discourage its use, I personally prefer to create a subclass. – Aritzbn Mar 16 '23 at 08:59
  • I agree `dynamic` type is less performant. Just a suggestion to use it when you don't want to create a class for deserialization. – Bhuvaneshwaran Mar 16 '23 at 09:17
  • Unless it is strictly necessary I will avoid using it, but I appreciate your answer :) – Aritzbn Mar 16 '23 at 09:19
0

the simpliest way to get JobId, is to add a JsonConstructor to your class

var myObject = JsonConvert.DeserializeObject<MyObject>(response);

public class MyObject
{
    // ... your another properties

    public string JobId { get; set; }
    
    public MyObject(JObject job)
    {
        JobId = (string) job["id"];
    }
}

another way is to add a private field job to your class. It makes sense if you need to serialize back later

public class MyObject
{
   // ... your another properties

    [JsonProperty("job")]
    private JObject job;

    [JsonIgnore]
    public string JobId
    {
        get { return (string)job["id"]; }
        set { job["id"] = value; }
    }
}
Serge
  • 40,935
  • 4
  • 18
  • 45