C#: List All Work Items in an Azure DevOps Project

Posted on 29th April 2020

In an earlier tutorial, C#: Creating Work Items in Azure DevOps using REST API, you learned how to consume Azure DevOps REST API methods in a C# console application to create new work items. In this post, we will create a similar C# console application but this app will get all Work Items from an Azure DevOps project.

Every work item in Azure DevOps project has a unique ID, so if you know the ID you could easily retrieve that work item using the following endpoint URI.

GET https://dev.azure.com/{organization}/{project}/_apis/wit/workitems/{id}?api-version=5.1

However, if you donít know the work items IDs you can send a request to the following endpoint URI and get the IDs of all Work Items within the specified backlog.

GET https://dev.azure.com/{organization}/{project}/{team}/_apis/work/backlogs/{backlogId}/workItems?api-version=5.1-preview.1

This is exactly what this program will do. It will first get all the Work Items Ids within a backlog and then iterate through each ID to call the Get work item API for each of those IDs.

Program Logic

The first step is to get the ids of all Work Items within a backlog. A project may have different backlogs like Epic, Requirement and Task. The following endpoint returns a list of all backlogs in a project.

GET https://dev.azure.com/{organization}/{project}/{team}/_apis/work/backlogs?api-version=5.1-preview.1

In this program, we will use the backlog level Requirement and the id for this backlog level is Microsoft.Requirement.

The Azure class defines various environment settings such as organization name, project name, project team, so on and so forth.

The SendRequest method uses HttpClient class to send an asynchronous HTTP GET request to the endpoint URI.

The first request to get work items within a backlog returns a JSON that contains an array of workitems. The C# representation of this response JSON is defined in the program using classes WorkItemsList, Workitem and Target.

The JSON is deserialized and the IDs are combined to a comma-separated list. This list is passed to the following endpoint URL to list all the work items.

GET https://dev.azure.com/{organization}/{project}/_apis/wit/workitems?ids={ids}&api-version=5.1

Program source code

Here is the full source code.

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http;
using System.Net.Http.Headers;
using Newtonsoft.Json; // Install Newtonsoft.Json from Nuget

namespace DevOpsWorkItems
{
    class Program
    {
        public class WorkItemsList
        {
            public Workitem[] workItems { get; set; }
        }

        public class Workitem
        {
            public object rel { get; set; }
            public object source { get; set; }
            public Target target { get; set; }
        }

        public class Target
        {
            public int id { get; set; }
        }
        
        static class Azure
        {
            public const string BASE = "https://dev.azure.com";
            public const string PAT = "3ljqhiwlkowddiqscp2xd6nd3rwfs2g6vs5yfaeg2kcdzsgi264a";
            public const string ORG = "OpenTechGuides";
            public const string API = "api-version=5.1-preview";
            public const string PROJECT = "OTGRESTDemo";
            public const string PROJECT_TEAM = "OTGRESTDemoTeam";
            public const string BACKLOG_ID = "Microsoft.RequirementCategory";
        }
    
	 static void Main(string[] args)
	 {
	   // Create and initialize HttpClient instance.      
	   HttpClient client = new HttpClient();
             
	  // Set Media Type of Response.
	   client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                
	  // Generate base64 encoded authorization header
	   client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0}:{1}", "", Azure.PAT))));

       // Get all work item ids in backlog
	   string BackLogWorkItemsURI = String.Join("?", String.Join("/", Azure.BASE, Azure.ORG, Azure.PROJECT, Azure.PROJECT_TEAM, "_apis/work/backlogs" , Azure.BACKLOG_ID, "/workItems"), Azure.API);
       Console.WriteLine(BackLogWorkItemsURI);
       string result = SendRequest(client, BackLogWorkItemsURI).Result;
       WorkItemsList workitemlist = JsonConvert.DeserializeObject<WorkItemsList>(result);

            // Combine workitem ids as a comma separated list.
            List<int> ids = new List<int>();
            foreach (Workitem wit in workitemlist.workItems)
            {
                ids.Add(wit.target.id);
            }

            // Build URI to get details of all workitems
            string workItemListURI = String.Join("/", Azure.BASE, Azure.ORG, Azure.PROJECT, "_apis/wit/workitems?ids=");
            workItemListURI += String.Join("&", String.Join(",", ids), Azure.API);
            Console.WriteLine(workItemListURI);
            result = SendRequest(client, workItemListURI).Result;

            // Pretty print the JSON
            dynamic witem = JsonConvert.DeserializeObject<object>(result);
            Console.WriteLine(JsonConvert.SerializeObject(witem, Formatting.Indented));

            Console.ReadLine();
            client.dispose();
        
	} // End of Main
    
      // Send HTTP GET Request and get response
        public static async Task<string> SendRequest(HttpClient client, string uri)
        {
            try
            {
                using (HttpResponseMessage response = await client.GetAsync(uri))
                {
                    response.EnsureSuccessStatusCode();
                    return (await response.Content.ReadAsStringAsync());
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                return string.Empty;
            }
        } // End of SendRequest method

       
	}
 }

Post a comment

Comments

Nothing yet..be the first to share wisdom.