Trying to read commits from azure devops rest api results in redirects

61 Views Asked by At

I am trying to get a list of commits. The execution waits forever on getting repoResponse.

Why?

When I paste the url (getting it from hovering repoUri in visual studio), I am never prompted for a basic auth password but I get redirected to a login page.

public async Task ListCommits()
{
    var pat = ConfigurationManager.AppSettings["PAT"];
    var encodedPat = Convert.ToBase64String(Encoding.ASCII.GetBytes($":{pat}"));

    using (var client = new HttpClient())
    {
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", encodedPat);
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        var repoUri = $"https://dev.azure.com/{organization}/{project}/_apis/git/repositories/{repository}?api-version=6.0";
        var repoResponse = await client.GetAsync(repoUri);
        if (!repoResponse.IsSuccessStatusCode)
        {
            Console.WriteLine($"Failed to retrieve repository. Status code: {repoResponse.StatusCode}");
            return;
        }

        string repoResponseContent = await repoResponse.Content.ReadAsStringAsync();
        var repo = JObject.Parse(repoResponseContent);
        var repoId = repo["id"].ToString();

        var commitsUri = $"https://dev.azure.com/{organization}/{project}/_apis/git/repositories/{repoId}/commits?searchCriteria.itemVersion.version=master&api-version=6.0";
        var commitsResponse = await client.GetAsync(commitsUri);
        if (!commitsResponse.IsSuccessStatusCode)
        {
            Console.WriteLine($"Failed to retrieve commits. Status code: {commitsResponse.StatusCode}");
            return;
        }

        string commitsContent = await commitsResponse.Content.ReadAsStringAsync();
        Console.WriteLine("Commits Response:");
        Console.WriteLine(commitsContent);

        var commitsData = Newtonsoft.Json.Linq.JObject.Parse(commitsContent);
        foreach (var commit in commitsData["value"])
        {
            var commitId = commit["commitId"].ToString();
            var changesUri = $"https://dev.azure.com/{organization}/{project}/_apis/git/repositories/{repoId}/commits/{commitId}/changes?api-version=6.0";
            var changesResponse = await client.GetAsync(changesUri);
            if (changesResponse.IsSuccessStatusCode)
            {
                string changesContent = await changesResponse.Content.ReadAsStringAsync();
                Console.WriteLine($"Changes for Commit ID {commitId}:");
                Console.WriteLine(changesContent);
            }
            else
            {
                Console.WriteLine($"Failed to retrieve changes for commit {commitId}. Status code: {changesResponse.StatusCode}");
            }
        }
    }
}

curl

I also tried to use curl to fetch the repoUri. Organization and Project and TheRepo are actually something else.

curl -u :theencodepath= https://dev.azure.com/Organization/Project/_apis/git/repositories/TheRepo?api-version=6.0

The result starts like:

<html><head><title>Object moved</title></head><body>
<h2>Object moved to <a href="https://spsprodeus21.vssps.visualstudio.com/_signin?realm=de
1

There are 1 best solutions below

16
Kevin Lu-MSFT On

From your code sample, you are using the ConfigurationManager.AppSettings["PAT"] to read the PAT from the app.config file.

If the PAT token doesn't exists, it will redirect to a login page.

I can reproduce the same issue when using the same code sample.

enter image description here

To solve this issue, you need to add an app.config file to your project.

For example:

enter image description here

Then you can add the PAT value to the app.config file.

For example:

<configuration>

    <appSettings>
        <add key="PAT" value="PAT Token Value"/>
    </appSettings>
</configuration>

When you run the C# Project, it will read the PAT from the app.config file and run the Rest API to get the commits.

Result:

enter image description here

Update:

Full sample code:

using Microsoft.IdentityModel.Protocols;
using Newtonsoft.Json.Linq;
using System.Configuration;
using System.Net.Http.Headers;
using System.Text;

namespace ClassLibrary1
{
    class Program

    {
        static async Task Main(string[] args)
        {
            var pat = ConfigurationManager.AppSettings["PAT"];
            var encodedPat = Convert.ToBase64String(Encoding.ASCII.GetBytes($":{pat}"));

            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", encodedPat);
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                var repoUri = $"https://dev.azure.com/{organization}/{project}/_apis/git/repositories/{reponame}?api-version=6.0";
                var repoResponse = await client.GetAsync(repoUri);
                if (!repoResponse.IsSuccessStatusCode)
                {
                    Console.WriteLine($"Failed to retrieve repository. Status code: {repoResponse.StatusCode}");
                    return;
                }

                string repoResponseContent = await repoResponse.Content.ReadAsStringAsync();
                var repo = JObject.Parse(repoResponseContent);
                var repoId = repo["id"].ToString();

                var commitsUri = $"https://dev.azure.com/{OrganizationName}/{Project}/_apis/git/repositories/{repoId}/commits?searchCriteria.itemVersion.version=master&api-version=6.0";
                var commitsResponse = await client.GetAsync(commitsUri);
                if (!commitsResponse.IsSuccessStatusCode)
                {
                    Console.WriteLine($"Failed to retrieve commits. Status code: {commitsResponse.StatusCode}");
                    return;
                }

                string commitsContent = await commitsResponse.Content.ReadAsStringAsync();
                Console.WriteLine("Commits Response:");
                Console.WriteLine(commitsContent);

                var commitsData = Newtonsoft.Json.Linq.JObject.Parse(commitsContent);
                foreach (var commit in commitsData["value"])
                {
                    var commitId = commit["commitId"].ToString();
                    var changesUri = $"https://dev.azure.com/{OrganizationName}/{ProjectName}/_apis/git/repositories/{repoId}/commits/{commitId}/changes?api-version=6.0";
                    var changesResponse = await client.GetAsync(changesUri);
                    if (changesResponse.IsSuccessStatusCode)
                    {
                        string changesContent = await changesResponse.Content.ReadAsStringAsync();
                        Console.WriteLine($"Changes for Commit ID {commitId}:");
                        Console.WriteLine(changesContent);
                    }
                    else
                    {
                        Console.WriteLine($"Failed to retrieve changes for commit {commitId}. Status code: {changesResponse.StatusCode}");
                    }
                }
            }
        }
    }
}

Update2:

Refer to this doc to create PAT: Use personal access tokens

enter image description here