VSTS BuildClient.GetArtifactContentZipAsync throws Microsoft.VisualStudio.Services.WebApi exception

Viewed 376

I'm trying to automate build artifact download. The objective is to download a specific build artifact. When I call BuildClient.GetArtifactContentZipAsync, it throws the following error

enter image description here

I am using the following code

        private static void DownloadBuildResults(Build StartedBuild, string ArtifactName)
        {
            //BuildArtifact drop = BuildClient.GetArtifactAsync(StartedBuild.Id, ArtifactName).Result; //get detiled info

            //Console.WriteLine("Build location: " + drop.Resource.DownloadUrl);

            //string dropFileName = String.Format("{0}_{1}.zip", StartedBuild.Definition.Name, StartedBuild.BuildNumber);

            Stream zipStream = BuildClient.GetArtifactContentZipAsync(79414, "abc").Result; //get content

            using (FileStream zipFile = new FileStream("abc.zip", FileMode.Create))
                zipStream.CopyTo(zipFile);

Please note that I buildID and artifact name is correct. I have double-checked these values. The above code example is taken from https://github.com/ashamrai/TFRestApi/blob/master/19.TFRestApiAppQueueBuild/TFRestApiApp/Program.cs

Is this a bug in the API/SDK? or Am I doing something wrong?

Here is the sample code if someone wants to give a try GIST: https://gist.github.com/abhishekgoenka/9759256f995e7f7c9cbcb7872c8591c0

I get following error in code enter image description here

Stack trace

   at Microsoft.VisualStudio.Services.WebApi.VssHttpClientBase.<HandleResponseAsync>d__53.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.VisualStudio.Services.WebApi.VssHttpClientBase.<SendAsync>d__51.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.TeamFoundation.Build.WebApi.BuildHttpClientBase.<GetArtifactContentZipAsync>d__10.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Utils.Dashboard.FrmAzureDashboard.<BtnDownloadKHP_Click>d__13.MoveNext() in C:\code\MetaFXTools\ui\Utils\Dashboard\FrmAzureDashboard.cs:line 118
3 Answers

I have hit the same issue as well.

What I have determined so far is that the call to GetArtifactContentZipAsync results in a 302 response from the server.

(The Location header in the response is along the lines of: https://artproduks1.artifacts.visualstudio.com/.../_apis/artifact/.../content?format=zip)

Inside of GetArtifactContentZipAsync is a call to httpResponseMessage.EnsureSuccessStatusCode() and this causes the error to be thrown as the library is not expecting a redirect to be returned. It is possible to create the connection using: new VssConnection(uri, creds, new VssClientHttpRequestSettings{AllowAutoRedirect = true}), so that the redirect is followed, however this then errors with a different message indicating that an incorrect version has been sent to the server.

I got to know the reason of the exception being thrown when calling this API. In the pipeline if you are using the "Publish build artifacts" to publish the artifacts, the API will work fine. Whereas if you use "Publish pipeline artifact" task, the API will return 302 ("Found").

Microsoft currently has no workaround for this issue and I would suggest you to use either HttpClient or WebClient to download the artifacts.

Is this a bug in the API/SDK? or Am I doing something wrong?

I can confirm the code from ashamrai is correct.(I tested it with my VS2019 16.6 and it works well.) And there's could be something with the values of your variables. I suggest you use try-catch to call the DownloadBuildResults function so that you can share detailed error message here. I just changed a bit from your code above:

class Program
{
    
    static readonly string TFUrl = "https://dev.azure.com/YourOrganizationName/";
    static readonly string UserPAT = "YourPAT";

    static void Main(string[] args)
    {
        try
        {
            int buildId = 832; // update to an existing build definition id
            string artifactName = "drop"; //default artifact name
            ConnectWithPAT(TFUrl, UserPAT);
            Stream zipStream = BuildClient.GetArtifactContentZipAsync(buildId, artifactName).Result; //get content
            using (FileStream zipFile = new FileStream(@"C:\MySite\test.zip", FileMode.Create))
                zipStream.CopyTo(zipFile);
            Console.WriteLine("Done");
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception: " + ex.Message);
            if (ex.InnerException != null) Console.WriteLine("Detailed Info: " + ex.InnerException.Message);
            Console.WriteLine("Stack:\n" + ex.StackTrace);
        }
    }
}

So you need to make sure:

1.You have a valid PAT which hasn't expired yet, and this PAT has the access to build artifact. Then directly enter the pat in static readonly string UserPAT = "xxxxxxxxxxxxx";. It should be "PAT" instead of "<PAT>".

2.The URL(TFUrl) only needs OrganizationName as part of it.

3.Make sure you choose the correct artifact name.

4.Distinguish the difference between BuildID and BuildDefinitionID.

  • You can see buildDefinitionID when editing the pipeline:

enter image description here

  • You can see BuildID when checking the pipeline run results in web portal:

enter image description here

You should use the BuildID as input.

5.Also, the build you run(BuildID) should have the artifact published:

enter image description here

Your pipeline should have Publish build artifacts task. Check the log and make sure something is published, the folder to be published can't be empty.

6.Since you're only testing the code by Download artifact function, make sure you queue/run the build successfully before your run the code. (Wait for the end of the pipeline run.)

Related