none
How to get key values from a nested Json RRS feed

  • Question

  • I have created an Azure Function which gets triggered from service webhook created in Azure Devops. The values returned from this service hook to me are in the form of nested json.

    {
      "subscriptionId": "6ab9dc9a-f7cd-4e97-8288-1e1cca983e65",
      "notificationId": 23,
      "id": "8897cc21-8d79-4194-964f-6228f34e2a67",
      "eventType": "workitem.updated",
      "publisherId": "tfs",
      "message": {
        "text": "Product Backlog Item #9 (PBI B) updated by Siddharth Shailesh Mehta\r\n(https://dev.azure.com/Sid-Demos/web/wi.aspx?pcguid=4d93d7c6-f39c-4fcb-97c4-dd02654eaf3a&id=9)",
        "html": "<a href=\"https://dev.azure.com/Sid-Demos/web/wi.aspx?pcguid=4d93d7c6-f39c-4fcb-97c4-dd02654eaf3a&amp;id=9\">Product Backlog Item #9</a> (PBI B) updated by Siddharth Shailesh Mehta",
        "markdown": "[Product Backlog Item #9](https://dev.azure.com/Sid-Demos/web/wi.aspx?pcguid=4d93d7c6-f39c-4fcb-97c4-dd02654eaf3a&id=9) (PBI B) updated by Siddharth Shailesh Mehta"
      },
      "detailedMessage": {
        "text": "Product Backlog Item #9 (PBI B) updated by Siddharth Shailesh Mehta\r\n(https://dev.azure.com/Sid-Demos/web/wi.aspx?pcguid=4d93d7c6-f39c-4fcb-97c4-dd02654eaf3a&id=9)\r\n\r\n",
        "html": "<a href=\"https://dev.azure.com/Sid-Demos/web/wi.aspx?pcguid=4d93d7c6-f39c-4fcb-97c4-dd02654eaf3a&amp;id=9\">Product Backlog Item #9</a> (PBI B) updated by Siddharth Shailesh Mehta<ul></ul>",
        "markdown": "[Product Backlog Item #9](https://dev.azure.com/Sid-Demos/web/wi.aspx?pcguid=4d93d7c6-f39c-4fcb-97c4-dd02654eaf3a&id=9) (PBI B) updated by Siddharth Shailesh Mehta\r\n\r\n"
      },
      "resource": {
        "id": 10,
        "workItemId": 9,
        "rev": 6,
        "revisedBy": {
          "id": "2d3a6041-0cfc-4ec9-8b8b-65dbd3440fbf",
          "name": "Siddharth Shailesh Mehta <mehta.siddharth87@gmail.com>",
          "displayName": "Siddharth Shailesh Mehta",
          "url": "https://spsprodsin1.vssps.visualstudio.com/A62c35866-5d3b-48f1-a9e0-ec58dae1a44e/_apis/Identities/2d3a6041-0cfc-4ec9-8b8b-65dbd3440fbf",
          "_links": {
            "avatar": {
              "href": "https://dev.azure.com/Sid-Demos/_apis/GraphProfile/MemberAvatars/msa.NWYwMTY2NjAtYWZhNy03YmUxLWJhMDMtMjc5MzkxMjVjOTE2"
            }
          },
          "uniqueName": "mehta.siddharth87@gmail.com",
          "imageUrl": "https://dev.azure.com/Sid-Demos/_apis/GraphProfile/MemberAvatars/msa.NWYwMTY2NjAtYWZhNy03YmUxLWJhMDMtMjc5MzkxMjVjOTE2",
          "descriptor": "msa.NWYwMTY2NjAtYWZhNy03YmUxLWJhMDMtMjc5MzkxMjVjOTE2"
        },
        "revisedDate": "9999-01-01T00:00:00Z",
        "fields": {
          "System.Rev": {
            "oldValue": 5,
            "newValue": 6
          },
          "System.AuthorizedDate": {
            "oldValue": "2019-10-14T18:10:12.983Z",
            "newValue": "2019-10-16T05:11:01.397Z"
          },
          "System.RevisedDate": {
            "oldValue": "2019-10-16T05:11:01.397Z",
            "newValue": "9999-01-01T00:00:00Z"
          },
          "System.ChangedDate": {
            "oldValue": "2019-10-14T18:10:12.983Z",
            "newValue": "2019-10-16T05:11:01.397Z"
          },
          "System.Watermark": {
            "oldValue": 80,
            "newValue": 84
          },
          "System.Description": {
            "newValue": "<div><span>some trigger data added</span></div>"
          }
        },
        "_links": {
          "self": {
            "href": "https://dev.azure.com/Sid-Demos/dd14a72e-8d38-4a99-ac1f-488499500d9a/_apis/wit/workItems/9/updates/10"
          },
          "workItemUpdates": {
            "href": "https://dev.azure.com/Sid-Demos/dd14a72e-8d38-4a99-ac1f-488499500d9a/_apis/wit/workItems/9/updates"
          },
          "parent": {
            "href": "https://dev.azure.com/Sid-Demos/dd14a72e-8d38-4a99-ac1f-488499500d9a/_apis/wit/workItems/9"
          },
          "html": {
            "href": "https://dev.azure.com/Sid-Demos/web/wi.aspx?pcguid=4d93d7c6-f39c-4fcb-97c4-dd02654eaf3a&id=9"
          }
        },
        "url": "https://dev.azure.com/Sid-Demos/dd14a72e-8d38-4a99-ac1f-488499500d9a/_apis/wit/workItems/9/updates/10",
        "revision": {
          "id": 9,
          "rev": 6,
          "fields": {
            "System.AreaPath": "PlanTrackWork",
            "System.TeamProject": "PlanTrackWork",
            "System.IterationPath": "PlanTrackWork\\Sprint 1",
            "System.WorkItemType": "Product Backlog Item",
            "System.State": "New",
            "System.Reason": "New backlog item",
            "System.CreatedDate": "2019-07-25T06:26:38.067Z",
            "System.CreatedBy": "Siddharth Shailesh Mehta <mehta.siddharth87@gmail.com>",
            "System.ChangedDate": "2019-10-16T05:11:01.397Z",
            "System.ChangedBy": "Siddharth Shailesh Mehta <mehta.siddharth87@gmail.com>",
            "System.CommentCount": 0,
            "System.Title": "PBI B",
            "System.BoardColumn": "New",
            "System.BoardColumnDone": false,
            "Microsoft.VSTS.Common.StateChangeDate": "2019-07-25T06:26:38.067Z",
            "Microsoft.VSTS.Common.Priority": 2,
            "Microsoft.VSTS.Common.ValueArea": "Business",
            "Microsoft.VSTS.Scheduling.Effort": 9.0,
            "Microsoft.VSTS.Common.BacklogPriority": 1999910559.0,
            "WEF_4C46EB8309FF4FB5A75794E2B8352A68_Kanban.Column": "New",
            "WEF_4C46EB8309FF4FB5A75794E2B8352A68_Kanban.Column.Done": false,
            "System.Description": "<div><span>some trigger data added</span></div>",
            "System.Parent": 15
          },
          "relations": [
            {
              "rel": "System.LinkTypes.Hierarchy-Reverse",
              "url": "https://dev.azure.com/Sid-Demos/dd14a72e-8d38-4a99-ac1f-488499500d9a/_apis/wit/workItems/15",
              "attributes": {
                "isLocked": false,
                "name": "Parent"
              }
            },
            {
              "rel": "System.LinkTypes.Hierarchy-Forward",
              "url": "https://dev.azure.com/Sid-Demos/dd14a72e-8d38-4a99-ac1f-488499500d9a/_apis/wit/workItems/21",
              "attributes": {
                "isLocked": false,
                "name": "Child"
              }
            },
            {
              "rel": "System.LinkTypes.Hierarchy-Forward",
              "url": "https://dev.azure.com/Sid-Demos/dd14a72e-8d38-4a99-ac1f-488499500d9a/_apis/wit/workItems/19",
              "attributes": {
                "isLocked": false,
                "name": "Child"
              }
            },
            {
              "rel": "System.LinkTypes.Hierarchy-Forward",
              "url": "https://dev.azure.com/Sid-Demos/dd14a72e-8d38-4a99-ac1f-488499500d9a/_apis/wit/workItems/20",
              "attributes": {
                "isLocked": false,
                "name": "Child"
              }
            }
          ],
          "_links": {
            "self": {
              "href": "https://dev.azure.com/Sid-Demos/dd14a72e-8d38-4a99-ac1f-488499500d9a/_apis/wit/workItems/9/revisions/6"
            },
            "workItemRevisions": {
              "href": "https://dev.azure.com/Sid-Demos/dd14a72e-8d38-4a99-ac1f-488499500d9a/_apis/wit/workItems/9/revisions"
            },
            "parent": {
              "href": "https://dev.azure.com/Sid-Demos/dd14a72e-8d38-4a99-ac1f-488499500d9a/_apis/wit/workItems/9"
            }
          },
          "url": "https://dev.azure.com/Sid-Demos/dd14a72e-8d38-4a99-ac1f-488499500d9a/_apis/wit/workItems/9/revisions/6"
        }
      },
      "resourceVersion": "1.0",
      "resourceContainers": {
        "collection": {
          "id": "4d93d7c6-f39c-4fcb-97c4-dd02654eaf3a",
          "baseUrl": "https://dev.azure.com/Sid-Demos/"
        },
        "account": {
          "id": "62c35866-5d3b-48f1-a9e0-ec58dae1a44e",
          "baseUrl": "https://dev.azure.com/Sid-Demos/"
        },
        "project": {
          "id": "dd14a72e-8d38-4a99-ac1f-488499500d9a",
          "baseUrl": "https://dev.azure.com/Sid-Demos/"
        }
      },
      "createdDate": "2019-10-16T05:11:08.1690642Z"
    }

    I want to extract values from this nested Json like System.WorkItemType and System.WorkItemId.

    I cannot convert this json to c# objects as the property name throws error on being named as System.WorkItemType or other variables. So I may need to escape them ( I guess)

    So any help on how to extract these values from nested Json, would be great.

    Thanks In Advance.


    Thursday, October 17, 2019 8:51 AM

Answers

  • Yes, you can. You can convert it to an object.. e.g.

    namespace ConsoleCS
    {
        using System;
        using System.IO;
        using Newtonsoft.Json;
        using Newtonsoft.Json.Linq;
    
        public class SampleClass
        {
            public SampleResource Resource { get; set; }
    
            public Guid SubscriptionID { get; set; }
    
            public override string ToString()
            {
                return $"{this.SubscriptionID} - {this.Resource.Revision.Fields.SystemWorkItemType}";
            }
        }
    
        public class SampleResource
        {
            public SampleRevision Revision { get; set; }
        }
    
        public class SampleRevision
        {
            public SampleFields Fields { get; set; }
        }
    
        public class SampleFields
        {
            [JsonProperty("System.WorkItemType")]
            public string SystemWorkItemType { get; set; }
        }
    
        public class Program
        {
            public static void Main(string[] args)
            {
                string sampleJson = File.ReadAllText(@"C:\Temp\test.json");
                JObject sample = (JObject)JsonConvert.DeserializeObject(sampleJson);
                Console.WriteLine(sample["subscriptionId"]);
                Console.WriteLine(sample["resource"]["revision"]["fields"]["System.WorkItemType"]);
                Console.WriteLine("---");
    
                SampleClass sampleClass = JsonConvert.DeserializeObject<SampleClass>(sampleJson);
                Console.WriteLine(sampleClass);
                Console.WriteLine("---");
    
                Console.WriteLine("\nDone.");
                Console.ReadLine();
            }
        }
    }

    • Marked as answer by Siddy Boy Friday, October 18, 2019 5:43 AM
    Thursday, October 17, 2019 10:11 AM

All replies

  • Yes, you can. You can convert it to an object.. e.g.

    namespace ConsoleCS
    {
        using System;
        using System.IO;
        using Newtonsoft.Json;
        using Newtonsoft.Json.Linq;
    
        public class SampleClass
        {
            public SampleResource Resource { get; set; }
    
            public Guid SubscriptionID { get; set; }
    
            public override string ToString()
            {
                return $"{this.SubscriptionID} - {this.Resource.Revision.Fields.SystemWorkItemType}";
            }
        }
    
        public class SampleResource
        {
            public SampleRevision Revision { get; set; }
        }
    
        public class SampleRevision
        {
            public SampleFields Fields { get; set; }
        }
    
        public class SampleFields
        {
            [JsonProperty("System.WorkItemType")]
            public string SystemWorkItemType { get; set; }
        }
    
        public class Program
        {
            public static void Main(string[] args)
            {
                string sampleJson = File.ReadAllText(@"C:\Temp\test.json");
                JObject sample = (JObject)JsonConvert.DeserializeObject(sampleJson);
                Console.WriteLine(sample["subscriptionId"]);
                Console.WriteLine(sample["resource"]["revision"]["fields"]["System.WorkItemType"]);
                Console.WriteLine("---");
    
                SampleClass sampleClass = JsonConvert.DeserializeObject<SampleClass>(sampleJson);
                Console.WriteLine(sampleClass);
                Console.WriteLine("---");
    
                Console.WriteLine("\nDone.");
                Console.ReadLine();
            }
        }
    }

    • Marked as answer by Siddy Boy Friday, October 18, 2019 5:43 AM
    Thursday, October 17, 2019 10:11 AM
  • Copy the JSON to the clipboard. Then in Visual Studio go to a C# file (.cs). In the Edit menu select "Paste Special" | "Paste JSON as Classes". You will get something such as the following. You can use the classes to read the entire JSON file at once.

    public class Rootobject
    {
        public string subscriptionId { get; set; }
        public int notificationId { get; set; }
        public string id { get; set; }
        public string eventType { get; set; }
        public string publisherId { get; set; }
        public Message message { get; set; }
        public Detailedmessage detailedMessage { get; set; }
        public Resource resource { get; set; }
        public string resourceVersion { get; set; }
        public Resourcecontainers resourceContainers { get; set; }
        public DateTime createdDate { get; set; }
    }
    
    public class Message
    {
        public string text { get; set; }
        public string html { get; set; }
        public string markdown { get; set; }
    }
    
    public class Detailedmessage
    {
        public string text { get; set; }
        public string html { get; set; }
        public string markdown { get; set; }
    }
    
    public class Resource
    {
        public int id { get; set; }
        public int workItemId { get; set; }
        public int rev { get; set; }
        public Revisedby revisedBy { get; set; }
        public DateTime revisedDate { get; set; }
        public Fields fields { get; set; }
        public _Links1 _links { get; set; }
        public string url { get; set; }
        public Revision revision { get; set; }
    }
    
    public class Revisedby
    {
        public string id { get; set; }
        public string name { get; set; }
        public string displayName { get; set; }
        public string url { get; set; }
        public _Links _links { get; set; }
        public string uniqueName { get; set; }
        public string imageUrl { get; set; }
        public string descriptor { get; set; }
    }
    
    public class _Links
    {
        public Avatar avatar { get; set; }
    }
    
    public class Avatar
    {
        public string href { get; set; }
    }
    
    public class Fields
    {
        public SystemRev SystemRev { get; set; }
        public SystemAuthorizeddate SystemAuthorizedDate { get; set; }
        public SystemReviseddate SystemRevisedDate { get; set; }
        public SystemChangeddate SystemChangedDate { get; set; }
        public SystemWatermark SystemWatermark { get; set; }
        public SystemDescription SystemDescription { get; set; }
    }
    
    public class SystemRev
    {
        public int oldValue { get; set; }
        public int newValue { get; set; }
    }
    
    public class SystemAuthorizeddate
    {
        public DateTime oldValue { get; set; }
        public DateTime newValue { get; set; }
    }
    
    public class SystemReviseddate
    {
        public DateTime oldValue { get; set; }
        public DateTime newValue { get; set; }
    }
    
    public class SystemChangeddate
    {
        public DateTime oldValue { get; set; }
        public DateTime newValue { get; set; }
    }
    
    public class SystemWatermark
    {
        public int oldValue { get; set; }
        public int newValue { get; set; }
    }
    
    public class SystemDescription
    {
        public string newValue { get; set; }
    }
    
    public class _Links1
    {
        public Self self { get; set; }
        public Workitemupdates workItemUpdates { get; set; }
        public Parent parent { get; set; }
        public Html html { get; set; }
    }
    
    public class Self
    {
        public string href { get; set; }
    }
    
    public class Workitemupdates
    {
        public string href { get; set; }
    }
    
    public class Parent
    {
        public string href { get; set; }
    }
    
    public class Html
    {
        public string href { get; set; }
    }
    
    public class Revision
    {
        public int id { get; set; }
        public int rev { get; set; }
        public Fields1 fields { get; set; }
        public Relation[] relations { get; set; }
        public _Links2 _links { get; set; }
        public string url { get; set; }
    }
    
    public class Fields1
    {
        public string SystemAreaPath { get; set; }
        public string SystemTeamProject { get; set; }
        public string SystemIterationPath { get; set; }
        public string SystemWorkItemType { get; set; }
        public string SystemState { get; set; }
        public string SystemReason { get; set; }
        public DateTime SystemCreatedDate { get; set; }
        public string SystemCreatedBy { get; set; }
        public DateTime SystemChangedDate { get; set; }
        public string SystemChangedBy { get; set; }
        public int SystemCommentCount { get; set; }
        public string SystemTitle { get; set; }
        public string SystemBoardColumn { get; set; }
        public bool SystemBoardColumnDone { get; set; }
        public DateTime MicrosoftVSTSCommonStateChangeDate { get; set; }
        public int MicrosoftVSTSCommonPriority { get; set; }
        public string MicrosoftVSTSCommonValueArea { get; set; }
        public float MicrosoftVSTSSchedulingEffort { get; set; }
        public float MicrosoftVSTSCommonBacklogPriority { get; set; }
        public string WEF_4C46EB8309FF4FB5A75794E2B8352A68_KanbanColumn { get; set; }
        public bool WEF_4C46EB8309FF4FB5A75794E2B8352A68_KanbanColumnDone { get; set; }
        public string SystemDescription { get; set; }
        public int SystemParent { get; set; }
    }
    
    public class _Links2
    {
        public Self1 self { get; set; }
        public Workitemrevisions workItemRevisions { get; set; }
        public Parent1 parent { get; set; }
    }
    
    public class Self1
    {
        public string href { get; set; }
    }
    
    public class Workitemrevisions
    {
        public string href { get; set; }
    }
    
    public class Parent1
    {
        public string href { get; set; }
    }
    
    public class Relation
    {
        public string rel { get; set; }
        public string url { get; set; }
        public Attributes attributes { get; set; }
    }
    
    public class Attributes
    {
        public bool isLocked { get; set; }
        public string name { get; set; }
    }
    
    public class Resourcecontainers
    {
        public Collection collection { get; set; }
        public Account account { get; set; }
        public Project project { get; set; }
    }
    
    public class Collection
    {
        public string id { get; set; }
        public string baseUrl { get; set; }
    }
    
    public class Account
    {
        public string id { get; set; }
        public string baseUrl { get; set; }
    }
    
    public class Project
    {
        public string id { get; set; }
        public string baseUrl { get; set; }
    }
    



    Sam Hobbs
    SimpleSamples.Info

    Thursday, October 17, 2019 4:07 PM
  • Hi Siddy,

    Thank you for posting here.

    For your question, you want to get extract values from this nested Json.

    First of all, you could add a nugget package: Newtonsoft.Json.

    And then you could try the following code to get it.

            static void Main(string[] args)
            {
                string jsonfile = @"D:\test\test.json";
                using (System.IO.StreamReader file = System.IO.File.OpenText(jsonfile))
                {
                    using (JsonTextReader reader = new JsonTextReader(file))
                    {
                        JObject o = (JObject)JToken.ReadFrom(reader);
                     
                        JToken workItemType = o["resource"]["revision"]["fields"]["System.WorkItemType"];
                        JToken workItemId = o["resource"]["workItemId"];
    
                        Console.WriteLine("WorkItemType: "+workItemType.ToString());
                        Console.WriteLine("WorkItemId: "+ workItemId.ToString());
                    }
                }
                Console.ReadKey();
            }
    

    Result:

    Hope my solution could be helpful.

    Best regards,

    Timon


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Friday, October 18, 2019 3:26 AM
  • Hey thanks for the answer, appreciate it. I got to know a new cool feature about Json pasting as I was not aware.

    This seems like a good approach, and should be the case, but I am getting all null values when I parse my Json.

    Following is my code:
    Rootobject ro = new Rootobject();             
    
                var values = JsonConvert.DeserializeObject<Rootobject>(jsonVal);
    
                var check = JsonConvert.SerializeObject(ro);
    
                ro.resource.revision.fields.SystemAreaPath = values.resource.revision.fields.SystemAreaPath;
                ro.resource.revision.fields.SystemIterationPath = values.resource.revision.fields.SystemIterationPath;

    Friday, October 18, 2019 4:49 AM
  • Hey thanks for the response. Appreciate it. I got to work with the above solution and was able to fetch the data.

    Just one note is that I had to cast the data with sample, so say for e.g., but overall I was able to extract values.

    (string)sample["subscriptionId"]
    Friday, October 18, 2019 5:43 AM
  • Hey thanks for the reply, much appreciated. The above solution works if I want to read from a Json text file saved at a specified path.

    How to read the Json from say an API output. I tried tweaking the above solution, but could not get. Would be great if you can tweak the logic by playing once we have the json data.
    Friday, October 18, 2019 6:39 AM