Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Azure DevOps Services
Das Abrufen von Arbeitsaufgaben mithilfe von Abfragen ist ein gängiges Szenario in Azure DevOps Services. In diesem Artikel wird erläutert, wie Sie dieses Szenario programmgesteuert mithilfe von REST-APIs oder .NET Clientbibliotheken implementieren.
Tipp
Sie können KI verwenden, um diese Aufgabe zu unterstützen weiter unten in diesem Artikel, oder lesen Sie Enable AI-Unterstützung bei Azure DevOps MCP Server, um zu beginnen.
Voraussetzungen
| Kategorie | Anforderungen |
|---|---|
| Azure DevOps |
-
Eine Organisation – Zugriff auf ein Projekt mit Arbeitsaufgaben |
| Authentifizierung | Wählen Sie eine der folgenden Methoden: - Microsoft Entra ID Authentifizierung (empfohlen für interaktive Apps) - Dienstprinzipalauthentifizierung (empfohlen für Automatisierung) - Managed Identity authentication (empfohlen für Azure gehostete Apps) - Persönliches Zugriffstoken (zum Testen) |
| Entwicklungsumgebung | Eine C#-Entwicklungsumgebung. Sie können |
Von Bedeutung
Erwägen Sie die Verwendung der sichereren Microsoft Entra Token gegenüber höherer Gefahr personalen Zugriffstoken. Weitere Informationen finden Sie unter Reduzieren der PAT-Verwendung. Überprüfen Sie die Authentifizierungsanleitungen , um den richtigen Authentifizierungsmechanismus für Ihre Anforderungen auszuwählen.
Authentifizierungsoptionen
In diesem Artikel werden mehrere Authentifizierungsmethoden für verschiedene Szenarien veranschaulicht:
Microsoft Entra ID Authentifizierung (empfohlen für interaktive Apps)
Verwenden Sie für Produktionsanwendungen mit Benutzerinteraktion Microsoft Entra ID Authentifizierung:
<PackageReference Include="Microsoft.TeamFoundationServer.Client" Version="19.232.1" />
<PackageReference Include="Microsoft.VisualStudio.Services.InteractiveClient" Version="19.232.1" />
<PackageReference Include="Microsoft.Identity.Client" Version="4.67.2" />
Dienstprinzipalauthentifizierung (empfohlen für die Automatisierung)
Für automatisierte Szenarien, CI/CD-Pipelines und Serveranwendungen:
<PackageReference Include="Microsoft.TeamFoundationServer.Client" Version="19.232.1" />
<PackageReference Include="Microsoft.Identity.Client" Version="4.67.2" />
Verwaltete Identitätsauthentifizierung (empfohlen für Azure gehostete Apps)
Für Anwendungen, die auf Azure-Diensten ausgeführt werden (Funktionen, App-Dienst usw.):
<PackageReference Include="Microsoft.TeamFoundationServer.Client" Version="19.232.1" />
<PackageReference Include="Azure.Identity" Version="1.13.1" />
Authentifizierung über das persönliche Zugriffstoken
Für Entwicklungs- und Testszenarien:
<PackageReference Include="Microsoft.TeamFoundationServer.Client" Version="19.232.1" />
C#-Codebeispiele
Die folgenden Beispiele zeigen, wie Arbeitsaufgaben mithilfe verschiedener Authentifizierungsmethoden abgerufen werden.
Beispiel 1: Microsoft Entra ID-Authentifizierung (interaktiv)
Hinweis
Die in diesem Beispiel verwendete VssAadCredential-Klasse erfordert das Microsoft.VisualStudio.Services.InteractiveClient-Paket und zielt auf .NET Framework Verwenden Sie für .NET Core/.NET 5+-Anwendungen den msAL-basierten Ansatz, der in Example 2 (Service Principal) oder Example 3 (Managed Identity) mit VssOAuthAccessTokenCredential angezeigt wird.
// NuGet packages:
// Microsoft.TeamFoundationServer.Client
// Microsoft.VisualStudio.Services.InteractiveClient
// Microsoft.Identity.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 EntraIdQueryExecutor
{
private readonly Uri uri;
/// <summary>
/// Initializes a new instance using Microsoft Entra ID authentication.
/// </summary>
/// <param name="orgName">Your Azure DevOps organization name</param>
public EntraIdQueryExecutor(string orgName)
{
this.uri = new Uri("https://dev.azure.com/" + orgName);
}
/// <summary>
/// Execute a WIQL query using Microsoft Entra ID authentication.
/// </summary>
/// <param name="project">The name of your project within your organization.</param>
/// <returns>A list of WorkItem objects representing all the open bugs.</returns>
public async Task<IList<WorkItem>> QueryOpenBugsAsync(string project)
{
// Use Microsoft Entra ID authentication
var credentials = new VssAadCredential();
var wiql = new Wiql()
{
Query = "SELECT [System.Id], [System.Title], [System.State] " +
"FROM WorkItems " +
"WHERE [Work Item Type] = 'Bug' " +
"AND [System.TeamProject] = @project " +
"AND [System.State] <> 'Closed' " +
"ORDER BY [System.State] ASC, [System.ChangedDate] DESC",
};
using (var httpClient = new WorkItemTrackingHttpClient(this.uri, new VssCredentials(credentials)))
{
try
{
var result = await httpClient.QueryByWiqlAsync(wiql, project).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", "System.CreatedDate" };
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>
/// Print the results of the work item query.
/// </summary>
public async Task PrintOpenBugsAsync(string project)
{
var workItems = await this.QueryOpenBugsAsync(project).ConfigureAwait(false);
Console.WriteLine($"Query Results: {workItems.Count} items found");
foreach (var workItem in workItems)
{
Console.WriteLine($"{workItem.Id}\t{workItem.Fields["System.Title"]}\t{workItem.Fields["System.State"]}");
}
}
}
Beispiel 2: Dienstprinzipalauthentifizierung (automatisierte Szenarien)
// NuGet packages:
// Microsoft.TeamFoundationServer.Client
// Microsoft.Identity.Client
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Identity.Client;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;
using Microsoft.VisualStudio.Services.Common;
using Microsoft.VisualStudio.Services.WebApi;
public class ServicePrincipalQueryExecutor
{
private readonly Uri uri;
private readonly string clientId;
private readonly string clientSecret;
private readonly string tenantId;
/// <summary>
/// Initializes a new instance using Service Principal authentication.
/// </summary>
/// <param name="orgName">Your Azure DevOps organization name</param>
/// <param name="clientId">Service principal client ID</param>
/// <param name="clientSecret">Service principal client secret</param>
/// <param name="tenantId">Microsoft Entra tenant ID</param>
public ServicePrincipalQueryExecutor(string orgName, string clientId, string clientSecret, string tenantId)
{
this.uri = new Uri($"https://dev.azure.com/{orgName}");
this.clientId = clientId;
this.clientSecret = clientSecret;
this.tenantId = tenantId;
}
/// <summary>
/// Execute a WIQL query using Service Principal authentication.
/// </summary>
public async Task<IList<WorkItem>> QueryOpenBugsAsync(string project)
{
// Acquire token using Service Principal
var app = ConfidentialClientApplicationBuilder
.Create(this.clientId)
.WithClientSecret(this.clientSecret)
.WithAuthority($"https://login.microsoftonline.com/{this.tenantId}")
.Build();
var scopes = new[] { "https://app.vssps.visualstudio.com/.default" };
var result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
var credentials = new VssOAuthAccessTokenCredential(result.AccessToken);
var wiql = new Wiql()
{
Query = "SELECT [System.Id], [System.Title], [System.State] " +
"FROM WorkItems " +
"WHERE [Work Item Type] = 'Bug' " +
"AND [System.TeamProject] = @project " +
"AND [System.State] <> 'Closed' " +
"ORDER BY [System.State] ASC, [System.ChangedDate] DESC",
};
using (var httpClient = new WorkItemTrackingHttpClient(this.uri, new VssCredentials(credentials)))
{
try
{
var queryResult = await httpClient.QueryByWiqlAsync(wiql, project).ConfigureAwait(false);
var ids = queryResult.WorkItems.Select(item => item.Id).ToArray();
if (ids.Length == 0)
{
return Array.Empty<WorkItem>();
}
var fields = new[] { "System.Id", "System.Title", "System.State", "System.CreatedDate" };
return await httpClient.GetWorkItemsAsync(ids, fields, queryResult.AsOf).ConfigureAwait(false);
}
catch (Exception ex)
{
Console.WriteLine($"Error querying work items: {ex.Message}");
return Array.Empty<WorkItem>();
}
}
}
}
Beispiel 3: Verwaltete Identitätsauthentifizierung (Azure gehostete Apps)
// NuGet packages:
// Microsoft.TeamFoundationServer.Client
// Azure.Identity
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Azure.Core;
using Azure.Identity;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;
using Microsoft.VisualStudio.Services.Common;
using Microsoft.VisualStudio.Services.WebApi;
public class ManagedIdentityQueryExecutor
{
private readonly Uri uri;
/// <summary>
/// Initializes a new instance using Managed Identity authentication.
/// </summary>
/// <param name="orgName">Your Azure DevOps organization name</param>
public ManagedIdentityQueryExecutor(string orgName)
{
this.uri = new Uri($"https://dev.azure.com/{orgName}");
}
/// <summary>
/// Execute a WIQL query using Managed Identity authentication.
/// </summary>
public async Task<IList<WorkItem>> QueryOpenBugsAsync(string project)
{
// Use Managed Identity to acquire token
var credential = new DefaultAzureCredential();
var tokenRequestContext = new TokenRequestContext(new[] { "https://app.vssps.visualstudio.com/.default" });
var tokenResult = await credential.GetTokenAsync(tokenRequestContext);
var credentials = new VssOAuthAccessTokenCredential(tokenResult.Token);
var wiql = new Wiql()
{
Query = "SELECT [System.Id], [System.Title], [System.State] " +
"FROM WorkItems " +
"WHERE [Work Item Type] = 'Bug' " +
"AND [System.TeamProject] = @project " +
"AND [System.State] <> 'Closed' " +
"ORDER BY [System.State] ASC, [System.ChangedDate] DESC",
};
using (var httpClient = new WorkItemTrackingHttpClient(this.uri, new VssCredentials(credentials)))
{
try
{
var queryResult = await httpClient.QueryByWiqlAsync(wiql, project).ConfigureAwait(false);
var ids = queryResult.WorkItems.Select(item => item.Id).ToArray();
if (ids.Length == 0)
{
return Array.Empty<WorkItem>();
}
var fields = new[] { "System.Id", "System.Title", "System.State", "System.CreatedDate" };
return await httpClient.GetWorkItemsAsync(ids, fields, queryResult.AsOf).ConfigureAwait(false);
}
catch (Exception ex)
{
Console.WriteLine($"Error querying work items: {ex.Message}");
return Array.Empty<WorkItem>();
}
}
}
}
Beispiel 4: Authentifizierung des persönlichen Zugriffstokens
// NuGet package: 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 PatQueryExecutor
{
private readonly Uri uri;
private readonly string personalAccessToken;
/// <summary>
/// Initializes a new instance using Personal Access Token authentication.
/// </summary>
/// <param name="orgName">Your Azure DevOps organization name</param>
/// <param name="personalAccessToken">Your Personal Access Token</param>
public PatQueryExecutor(string orgName, string personalAccessToken)
{
this.uri = new Uri("https://dev.azure.com/" + orgName);
this.personalAccessToken = personalAccessToken;
}
/// <summary>
/// Execute a WIQL query using Personal Access Token authentication.
/// </summary>
/// <param name="project">The name of your project within your organization.</param>
/// <returns>A list of WorkItem objects representing all the open bugs.</returns>
public async Task<IList<WorkItem>> QueryOpenBugsAsync(string project)
{
var credentials = new VssBasicCredential(string.Empty, this.personalAccessToken);
var wiql = new Wiql()
{
Query = "SELECT [System.Id], [System.Title], [System.State] " +
"FROM WorkItems " +
"WHERE [Work Item Type] = 'Bug' " +
"AND [System.TeamProject] = @project " +
"AND [System.State] <> 'Closed' " +
"ORDER BY [System.State] ASC, [System.ChangedDate] DESC",
};
using (var httpClient = new WorkItemTrackingHttpClient(this.uri, new VssCredentials(credentials)))
{
try
{
var result = await httpClient.QueryByWiqlAsync(wiql, project).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", "System.CreatedDate" };
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>();
}
}
}
}
Verwendungsbeispiele
Die folgenden Beispiele veranschaulichen, wie jede Authentifizierungsklasse aufgerufen wird.
Verwendung der Microsoft Entra ID Authentifizierung (interaktiv)
class Program
{
static async Task Main(string[] args)
{
var executor = new EntraIdQueryExecutor("your-organization-name");
await executor.PrintOpenBugsAsync("your-project-name");
}
}
Verwenden der Dienstprinzipal-Authentifizierung (CI/CD-Szenarien)
class Program
{
static async Task Main(string[] args)
{
// These values should come from environment variables or Azure Key Vault
var clientId = Environment.GetEnvironmentVariable("AZURE_CLIENT_ID");
var clientSecret = Environment.GetEnvironmentVariable("AZURE_CLIENT_SECRET");
var tenantId = Environment.GetEnvironmentVariable("AZURE_TENANT_ID");
var executor = new ServicePrincipalQueryExecutor("your-organization-name", clientId, clientSecret, tenantId);
var workItems = await executor.QueryOpenBugsAsync("your-project-name");
Console.WriteLine($"Found {workItems.Count} open bugs via automation");
foreach (var item in workItems)
{
Console.WriteLine($"Bug {item.Id}: {item.Fields["System.Title"]}");
}
}
}
Verwenden der verwalteten Identitätsauthentifizierung (Azure Functions/App Service)
public class WorkItemQueryFunction
{
private readonly ILogger<WorkItemQueryFunction> _logger;
public WorkItemQueryFunction(ILogger<WorkItemQueryFunction> logger)
{
_logger = logger;
}
[Function("QueryOpenBugs")]
public async Task<HttpResponseData> Run(
[HttpTrigger(AuthorizationLevel.Function, "get")] HttpRequestData req)
{
var executor = new ManagedIdentityQueryExecutor("your-organization-name");
var workItems = await executor.QueryOpenBugsAsync("your-project-name");
var response = req.CreateResponse(System.Net.HttpStatusCode.OK);
await response.WriteAsJsonAsync(new {
Count = workItems.Count,
Items = workItems.Select(wi => new {
Id = wi.Id,
Title = wi.Fields["System.Title"],
State = wi.Fields["System.State"]
})
});
return response;
}
}
Verwenden der Authentifizierung für persönliche Zugriffstokens (Entwicklung/Tests)
class Program
{
static async Task Main(string[] args)
{
var pat = Environment.GetEnvironmentVariable("AZURE_DEVOPS_PAT"); // Never hardcode PATs
var executor = new PatQueryExecutor("your-organization-name", pat);
var workItems = await executor.QueryOpenBugsAsync("your-project-name");
Console.WriteLine($"Found {workItems.Count} open bugs");
foreach (var item in workItems)
{
Console.WriteLine($"Bug {item.Id}: {item.Fields["System.Title"]}");
}
}
}
Bewährte Methoden
Authentifizierung
- Use Microsoft Entra ID für interaktive Anwendungen mit Benutzeranmeldung
- Verwenden von Dienstprinzipalen für automatisierte Szenarien, CI/CD-Pipelines und Serveranwendungen
- Verwenden Sie verwaltete Identitäten für Anwendungen, die in Azure-Diensten (Functions, App Service, VMs) ausgeführt werden.
- Vermeiden Sie persönliche Zugriffstoken in der Produktion; Nur für Entwicklung und Tests verwendet
- Niemals Anmeldeinformationen im Quellcode fest codieren; verwenden Sie stattdessen Umgebungsvariablen oder Azure Key Vault.
- Implementierung der Rotation von Anmeldeinformationen für langzeitlaufende Anwendungen
- Sicherstellen der richtigen Berechtigungsbereiche – Arbeitsaufgabenabfragen erfordern geeignete Leseberechtigungen in Azure DevOps.
Fehlerbehandlung
- Implementieren Sie eine Rücksetzlogik mit exponentiellem Backoff für flüchtige Fehler
- Fehler angemessen protokollieren für Debugging und Monitoring
- Behandeln bestimmter Ausnahmen wie Authentifizierungsfehler und Netzwerktimeouts
- Verwenden Sie Abbruch-Token für lang andauernde Vorgänge
Leistung
- Abrufen von Batcharbeitselementen beim Abfragen mehrerer Elemente
- Einschränken von Abfrageergebnissen mithilfe der TOP-Klausel für große Datasets
- Zwischenspeichern häufig zugegriffener Daten , um API-Aufrufe zu reduzieren
- Verwenden sie geeignete Felder , um die Datenübertragung zu minimieren
Abfrageoptimierung
- Verwenden Sie bestimmte Feldnamen anstelle von SELECT * für eine bessere Leistung
- Fügen Sie die richtigen WHERE-Klauseln hinzu, um Ergebnisse auf dem Server zu filtern.
- Ordnen Sie die Ergebnisse entsprechend für Ihren Anwendungsfall an.
- Erwägen Sie Abfragegrenzwerte und Paginierung für große Resultsets
Problembehandlung
Authentifizierungsprobleme
- Microsoft Entra ID Authentifizierungsfehler – Stellen Sie sicher, dass der Benutzer über ordnungsgemäße Berechtigungen verfügt und bei Azure DevOps angemeldet ist.
- Serviceprinzipalauthentifizierungsfehler – Überprüfen, ob Client-ID, geheimer Schlüssel und Mandanten-ID korrekt sind; Überprüfen von Dienstprinzipalberechtigungen in Azure DevOps
- Managed Identity Authentication-Fehler – Stellen Sie sicher, dass die Azure Ressource eine verwaltete Identität aktiviert hat und ordnungsgemäße Berechtigungen besitzt.
-
PAT-Authentifizierungsfehler – Überprüfen, ob das Token gültig ist und über entsprechende Bereiche verfügt (
vso.workfür den Zugriff auf Arbeitsaufgaben) - Token-Ablauf – Überprüfen Sie, ob Ihr PAT (Personal Access Token) abgelaufen ist, und generieren Sie bei Bedarf einen neuen Token.
Abfrageprobleme
- Ungültige WIQL-Syntax – Stellen Sie sicher, dass die Syntax der Abfragesprache für Arbeitsaufgaben korrekt ist.
- Projektnamensfehler – Überprüfen, ob der Projektname vorhanden ist und richtig geschrieben ist
-
Feldnamenfehler - Verwenden Sie die richtigen Systemfeldnamen (z. B.
System.Id,System.Title)
Allgemeine Ausnahmen
- VssUnauthorizedException – Überprüfen von Anmeldeinformationen und Berechtigungen
- ArgumentException – Überprüfen, ob alle erforderlichen Parameter angegeben und gültig sind
- HttpRequestException – Überprüfen der Netzwerkkonnektivität und Dienstverfügbarkeit
Leistungsprobleme
- Langsame Abfragen – Hinzufügen geeigneter WHERE-Klauseln und Begrenzen von Ergebnismengen
- Speicherauslastung – Verarbeitung großer Ergebnismengen in Chargen
- Rate limiting – Implementieren von Wiederholungslogik mit exponentiellem Backoff
Verwenden von KI zum programmgesteuerten Abfragen von Arbeitsaufgaben
Wenn Sie den Azure DevOps MCP Server mit Ihrem KI-Agent im Agentmodus verbunden haben, können Sie Code für die Abfrage von Arbeitsaufgaben mithilfe natürlicher Sprachaufforderungen generieren.
| Aufgabe | Beispielaufforderung |
|---|---|
| Abfragecode generieren | Write C# code to query all active bugs assigned to me in Azure DevOps using the .NET client libraries with Microsoft Entra authentication |
| REST-API-Abfrage | Create a REST API call to fetch work items from Azure DevOps using a WIQL query with a personal access token |
| Ausführen einer gespeicherten Abfrage | Show me how to use the Azure DevOps .NET client to run a saved query and retrieve work item details including custom fields |
| In CSV exportieren | Build a .NET app that fetches work items from Azure DevOps and exports them to CSV using managed identity authentication |
| Nach Bereichspfad filtern | Write C# code to query work items under area path <Contoso\Backend> that were modified in the last 7 days |
| Paginieren großer Ergebnisse | Show me how to query Azure DevOps work items in batches of 200 using the .NET client libraries with proper pagination |
Hinweis
Der Agentmodus und der MCP-Server verwenden natürliche Sprache, sodass Sie diese Eingabeaufforderungen anpassen oder Nachverfolgungsfragen stellen können, um die Ergebnisse zu verfeinern.