Partilhar via


Obter itens de trabalho através de consultas de forma programática

Serviços de DevOps do Azure

Buscar itens de trabalho usando consultas é um cenário comum nos Serviços de DevOps do Azure. Este artigo explica como implementar esse cenário programaticamente usando APIs REST ou bibliotecas de cliente .NET.

Pré-requisitos

Categoria Requerimentos
Azure DevOps - Uma organização.<\br>- Um Token de Acesso Pessoal (PAT).
Ambiente de desenvolvimento Um ambiente de desenvolvimento C#. Você pode usar o Visual Studio.

Importante

Usamos Tokens de Acesso Pessoal (PATs) como exemplo neste artigo, mas não recomendamos o uso de PATs. Para obter mecanismos de autenticação mais seguros, consulte Diretrizes de autenticação.

Criar um projeto C# no Visual Studio

Para obter informações sobre programação C# no Visual Studio, consulte a documentação de programação do Visual Studio C#.

Conteúdo do código C#

As seguintes tarefas ocorrem no trecho de código:

  • Autenticar
    1. Crie credenciais usando seu Token de Acesso Pessoal (PAT).
    2. Gere o cliente utilizando as credenciais.
  • Obter os itens de trabalho
    1. Crie a consulta que deseja usar.
    2. Recupere os resultados dessa consulta.
    3. Buscar cada um dos itens de trabalho por ID.

Trecho de código C#

// nuget:Microsoft.TeamFoundationServer.Client
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;
using Microsoft.VisualStudio.Services.Common;
using Microsoft.VisualStudio.Services.WebApi;

public class QueryExecutor
{
    private readonly Uri uri;
    private readonly string personalAccessToken;

    /// <summary>
    /// Initializes a new instance of the <see cref="QueryExecutor" /> class.
    /// </summary>
    /// <param name="orgName">
    /// An organization in Azure DevOps Services. If you don't have one, you can create one for free:
    /// <see href="https://go.microsoft.com/fwlink/?LinkId=307137" />.
    /// </param>
    /// <param name="personalAccessToken">
    /// A Personal Access Token, find out how to create one:
    /// <see href="/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops" />.
    /// </param>
    public QueryExecutor(string orgName, string personalAccessToken)
    {
        this.uri = new Uri("https://dev.azure.com/" + orgName);
        this.personalAccessToken = personalAccessToken;
    }

    /// <summary>
    /// Execute a WIQL (Work Item Query Language) query to return a list of open bugs.
    /// </summary>
    /// <param name="project">The name of your project within your organization.</param>
    /// <returns>A list of <see cref="WorkItem"/> objects representing all the open bugs.</returns>
    public async Task<IList<WorkItem>> QueryOpenBugs(string project)
    {
        var credentials = new VssBasicCredential(string.Empty, this.personalAccessToken);
        var wiql = new Wiql()
        {
            Query = "Select [Id] " +
                    "From WorkItems " +
                    "Where [Work Item Type] = 'Bug' " +
                    "And [System.TeamProject] = '" + project + "' " +
                    "And [System.State] <> 'Closed' " +
                    "Order By [State] Asc, [Changed Date] Desc",
        };

        using (var httpClient = new WorkItemTrackingHttpClient(this.uri, new VssCredentials(credentials)))
        {
            try
            {
                var result = await httpClient.QueryByWiqlAsync(wiql).ConfigureAwait(false);
                var ids = result.WorkItems.Select(item => item.Id).ToArray();

                if (ids.Length == 0)
                {
                    return Array.Empty<WorkItem>();
                }

                var fields = new[] { "System.Id", "System.Title", "System.State" };
                return await httpClient.GetWorkItemsAsync(ids, fields, result.AsOf).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error querying work items: " + ex.Message);
                return Array.Empty<WorkItem>();
            }
        }
    }

    /// <summary>
    /// Execute a WIQL (Work Item Query Language) query to print a list of open bugs.
    /// </summary>
    /// <param name="project">The name of your project within your organization.</param>
    /// <returns>An async task.</returns>
    public async Task PrintOpenBugsAsync(string project)
    {
        var workItems = await this.QueryOpenBugs(project).ConfigureAwait(false);
        Console.WriteLine("Query Results: {0} items found", workItems.Count);

        foreach (var workItem in workItems)
        {
            Console.WriteLine(
                "{0}\t{1}\t{2}",
                workItem.Id,
                workItem.Fields["System.Title"],
                workItem.Fields["System.State"]);
        }
    }
}

Solucionar problemas

Ao trabalhar com o Azure DevOps programaticamente, você pode encontrar problemas relacionados à execução de consultas, uso de parâmetros ou sobrecargas de método. Esta secção fornece orientações sobre problemas comuns, as suas causas e como resolvê-los de forma eficaz. Ao entender essas etapas de solução de problemas, você pode garantir uma integração mais suave e evitar erros de tempo de execução.

Problemas comuns

  • Instanciação incorreta do Wiql objeto: verifique se o Wiql objeto está instanciado corretamente e contém uma consulta válida.
  • Uso incorreto de parâmetros opcionais: verifique se os parâmetros opcionais estão sendo passados corretamente, especialmente se forem nulos.
  • Sintaxe de consulta inválida: verifique se a Wiql consulta no objeto é válida e corresponde ao formato esperado.

RuntimeBinderException

Ao trabalhar com o método QueryByWiqlAsync no Azure DevOps, pode encontrar um RuntimeBinderException. Essa exceção normalmente ocorre quando os argumentos passados para o método não correspondem a nenhuma de suas sobrecargas. Compreender a assinatura do método e garantir o uso adequado do parâmetro pode ajudar a resolver esse problema.

Erro:
RuntimeBinderException: Esta exceção ocorre quando os argumentos passados para o QueryByWiqlAsync método não correspondem a nenhuma das sobrecargas do método.

Resolução:
Certifique-se de que os parâmetros que estão sendo passados para o método são dos tipos corretos e na ordem correta. A assinatura do método é a seguinte:

public virtual Task<WorkItemQueryResult> QueryByWiqlAsync(
    Wiql wiql,
    bool? continueOnError = null,
    int? top = null,
    object userState = null,
    CancellationToken cancellationToken = default(CancellationToken));

Código de exemplo com uso correto

O trecho de código a seguir demonstra o uso correto do QueryByWiqlAsync método, garantindo que os parâmetros sejam definidos corretamente:

using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;
using System;
using System.Threading.Tasks;
public async Task QueryWorkItemsAsync(WorkItemTrackingHttpClient client)
{
    var wiql = new Wiql()
    {
        Query = "SELECT [System.Id] FROM WorkItems WHERE [System.TeamProject] = 'YourProjectName'"
    };

    try
    {
        var result = await client.QueryByWiqlAsync(wiql);
        foreach (var workItem in result.WorkItems)
        {
            Console.WriteLine($"Work Item ID: {workItem.Id}");
        }
    }
    catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException ex)
    {
        Console.WriteLine($"Error: {ex.Message}");
    }
}

Explicação do código

  • Criar um Wiql objeto: o Wiql objeto contém a consulta para buscar itens de trabalho.
  • Call QueryByWiqlAsync: Passe o Wiql objeto para o método.
  • Manipular exceções: detete e RuntimeBinderException registre a mensagem de erro para depuração.

Seguindo esta abordagem, pode-se garantir o QueryByWiqlAsync uso adequado do método e evitar problemas comuns como RuntimeBinderException.