Read json value using C# without using Property

Viewed 254

I need to read the value of testCase.name for id 100000 from following JSON response string.

response = {
  "count": 2,
  "value": [
    {
      "id": 100000,
      "project": {
        "id": "aaaa-bbbb-cccc-dddd",
        "name": "MyTestProject",
        "url": "https://dev.azure.com/MyOrg/_apis/projects/MyTestProject"
      },      
      "testCase": { "name": "GetProjectTeamDetails" }
     }, 
    {
      "id": 100001,
      "project": {
        "id": "aaaa-bbbb-cccc-dddd",
        "name": "MyTestProject",
        "url": "https://dev.azure.com/MyOrg/_apis/projects/MyTestProject"
      },      
      "testCase": { "name": "QueueBuild" }      
    }
  ]
}

I've tried the following codes but could not achieve: Try1:

JObject o = JObject.Parse(response)
string testCaseName= (string)o["values"][0];

Try2:

 JObject jObject = JObject.Parse(response);
 string displayName = (string)jObject.SelectToken("testCase.name");
4 Answers

You could use

var jo = JObject.Parse(json);
var testCaseName  = (string)jo.SelectToken($"$.value[?(@id=={idToSearch})].testCase.name");

Update

Base on your question in comment, you could find the ID with test case name using

jo.SelectTokens($"$.value[?(@testCase.name=='{nameToSearch}')].id")

Please note in this case, you would need to use .SelectTokens as there is chances of duplicates as give in the example in OP. You could get all the results or the first based on your requirement.

var idList  = jo.SelectTokens($"$.value[?(@testCase.name=='{nameToSearch}')].id")
                 .Select(x=> long.Parse(x.ToString()));
var onlyFirst = (long)jo.SelectTokens($"$.value[?(@testCase.name=='{nameToSearch}')].id")
                 .First();

You need to step through hierarchy.

JObject jObject = JObject.Parse(jsonString);
var testCaseName = jObject.SelectToken("value[0].testCase.name").ToString();

Another approach is using dynamic keyword:

dynamic jt = JToken.Parse(response);
IEnumerable<dynamic> values = jt.value;
string name = values.FirstOrDefault(v => v.id == 100000)?.testCase.name;

The other answers have shown using SelectToken, which is fine - if you don't want to do that, you can still do it by accessing one property at a time:

using System;
using System.IO;
using Newtonsoft.Json.Linq;

class Test
{
    static void Main()
    {
        string json = File.ReadAllText("test.json");
        JObject obj = JObject.Parse(json);
        string testCase = (string) obj["value"][0]["testCase"]["name"];
        Console.WriteLine(testCase);
    }
}

In your Try1 you're using values instead of value, and you're stopping at the array - you're not asking for the testCase property, or the name property within that.

In your Try2 you're doing exactly the opposite - you're looking for testCase.name without selecting an element within the value array first.

As one third way, you could use dynamic typing:

using System;
using System.IO;
using Newtonsoft.Json.Linq;

class Test
{
    static void Main()
    {
        string json = File.ReadAllText("test.json");
        dynamic obj = JObject.Parse(json);
        string testCase = obj.value[0].testCase.name;
        Console.WriteLine(testCase);
    }
}
Related