Jegyzet
Az oldalhoz való hozzáférés engedélyezést igényel. Próbálhatod be jelentkezni vagy könyvtárat váltani.
Az oldalhoz való hozzáférés engedélyezést igényel. Megpróbálhatod a könyvtár váltását.
Azure DevOps Services
A munkaelemek lekérdezésekkel való lekérése gyakori forgatókönyv az Azure DevOps Servicesben. Ez a cikk bemutatja, hogyan implementálhatja ezt a forgatókönyvet programozott módon REST API-k vagy .NET-ügyfélkódtárak használatával.
Előfeltételek
| Kategória | Követelmények |
|---|---|
| Azure DevOps |
-
Egy szervezet – Hozzáférés munkahelyi elemeket tartalmazó projekthez |
| hitelesítés | Válasszon egyet a következő módszerek közül: - Microsoft Entra ID-hitelesítés (interaktív alkalmazásokhoz ajánlott) - Szolgáltatói Principal hitelesítés (automatizáláshoz ajánlott) - Felügyelt identitás hitelesítése (az Azure által üzemeltetett alkalmazásokhoz ajánlott) - Személyes hozzáférési jogkivonat (teszteléshez) |
| fejlesztési környezet | C#-fejlesztési környezet. Használhatja a Visual Studiót |
Fontos
Éles alkalmazások esetében a Személyes hozzáférési jogkivonatok (PAT-k) helyett a Microsoft Entra ID-hitelesítés használatát javasoljuk. A PAT-k tesztelési és fejlesztési forgatókönyvekhez alkalmasak. A megfelelő hitelesítési módszer kiválasztásával kapcsolatos útmutatásért tekintse meg a hitelesítési útmutatót.
Hitelesítési lehetőségek
Ez a cikk több hitelesítési módszert mutat be a különböző forgatókönyvek szerint:
Microsoft Entra ID-hitelesítés (interaktív alkalmazásokhoz ajánlott)
Felhasználói beavatkozással rendelkező éles alkalmazások esetén használja a Microsoft Entra ID-hitelesítést:
<PackageReference Include="Microsoft.TeamFoundationServer.Client" Version="19.225.1" />
<PackageReference Include="Microsoft.VisualStudio.Services.InteractiveClient" Version="19.225.1" />
<PackageReference Include="Microsoft.Identity.Client" Version="4.61.3" />
Szolgáltatási főszereplő hitelesítése (automatizáláshoz ajánlott)
Automatizált forgatókönyvek, CI-/CD-folyamatok és kiszolgálóalkalmazások esetén:
<PackageReference Include="Microsoft.TeamFoundationServer.Client" Version="19.225.1" />
<PackageReference Include="Microsoft.Identity.Client" Version="4.61.3" />
Felügyelt identitás hitelesítése (Az Azure által üzemeltetett alkalmazásokhoz ajánlott)
Azure-szolgáltatásokon (Functions, App Service stb.) futó alkalmazások esetén:
<PackageReference Include="Microsoft.TeamFoundationServer.Client" Version="19.225.1" />
<PackageReference Include="Azure.Identity" Version="1.10.4" />
Személyes hozzáférési jogkivonat hitelesítése
Fejlesztési és tesztelési forgatókönyvek esetén:
<PackageReference Include="Microsoft.TeamFoundationServer.Client" Version="19.225.1" />
C#-kód példák
Az alábbi példák bemutatják, hogyan lehet lekérni a feladatokat különböző hitelesítési módszerekkel.
1. példa: Microsoft Entra ID-hitelesítés (interaktív)
// 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).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"]}");
}
}
}
2. példa: Szolgáltatás főazonosító hitelesítés (automatizált forgatókönyvek)
// 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">Azure AD 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).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>();
}
}
}
}
3. példa: Felügyelt identitás hitelesítése (Azure által üzemeltetett alkalmazások)
// 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).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>();
}
}
}
}
4. példa: Személyes hozzáférési jogkivonat hitelesítése
// 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).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>();
}
}
}
}
Használati példák
Microsoft Entra ID-hitelesítés használata (interaktív)
class Program
{
static async Task Main(string[] args)
{
var executor = new EntraIdQueryExecutor("your-organization-name");
await executor.PrintOpenBugsAsync("your-project-name");
}
}
Szolgáltatásprincípál-hitelesítés használata (CI/CD-forgatókönyvek)
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"]}");
}
}
}
Felügyelt identitáshitelesítés (Azure Functions/App Service)
public class WorkItemQueryFunction
{
[FunctionName("QueryOpenBugs")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get")] HttpRequest req,
ILogger log)
{
var executor = new ManagedIdentityQueryExecutor("your-organization-name");
var workItems = await executor.QueryOpenBugsAsync("your-project-name");
return new OkObjectResult(new {
Count = workItems.Count,
Items = workItems.Select(wi => new {
Id = wi.Id,
Title = wi.Fields["System.Title"],
State = wi.Fields["System.State"]
})
});
}
}
Személyes hozzáférési jogkivonat-hitelesítés használata (fejlesztés/tesztelés)
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"]}");
}
}
}
Ajánlott eljárások
Hitelesítés
- A Microsoft Entra ID használata interaktív alkalmazásokhoz felhasználói bejelentkezéssel
- Szolgáltatásnév használata automatizált forgatókönyvekhez, CI-/CD-folyamatokhoz és kiszolgálóalkalmazásokhoz
- Felügyelt identitás használata Azure-szolgáltatásokon futó alkalmazásokhoz (Functions, App Service, virtuális gépek)
- Kerülje a személyes hozzáférési jogkivonatokat éles környezetben; csak fejlesztéshez és teszteléshez használható
- Soha ne kódoljon hitelesítő adatokat a forráskódban; környezeti változók vagy Azure Key Vault használata
- Hitelesítő adatok rotálásának implementálása hosszú ideig futó alkalmazásokhoz
- Megfelelő hatókörök biztosítása: A munkaelem-lekérdezésekhez megfelelő olvasási engedélyekre van szükség az Azure DevOpsban
Hibakezelés
- Újrapróbálkozási logika implementálása exponenciális visszalépéssel átmeneti hibák esetén
- Hibakereséshez és megfigyeléshez naplózza megfelelően a hibákat
- Bizonyos kivételek, például a hitelesítési hibák és a hálózati időtúllépések kezelése
- Lemondási tokenek használata hosszú ideig futó műveletekhez
Teljesítmény
- Több elem lekérdezésekor kötegelt munkaelem-lekérések
- Lekérdezési eredmények korlátozása nagy adathalmazok TOP záradékával
- Gyorsítótárazza a gyakran használt adatokat az API-hívások csökkentése érdekében
- A megfelelő mezők használata az adatátvitel minimalizálásához
Lekérdezésoptimalizálás
- A jobb teljesítmény érdekében használjon adott mezőneveket a SELECT * helyett
- Adjon hozzá megfelelő WHERE záradékokat az eredmények szűréséhez a kiszolgálón
- A használati esetnek megfelelő megrendelési eredmények
- Fontolja meg a lekérdezési korlátokat és a lapozást nagy eredményhalmazok esetén
Hibaelhárítás
Hitelesítési problémák
- Microsoft Entra-azonosító hitelesítési hibái: Győződjön meg arról, hogy a felhasználó rendelkezik a megfelelő engedélyekkel, és bejelentkezett az Azure DevOpsba
- Szolgáltatásnév hitelesítési hibái: Ellenőrizze, hogy az ügyfélazonosító, a titkos kód és a bérlőazonosító helyes-e; szolgáltatásnév-engedélyek ellenőrzése az Azure DevOpsban
- Felügyelt identitás hitelesítési hibái: Győződjön meg arról, hogy az Azure-erőforrás rendelkezik engedélyezett felügyelt identitással és megfelelő engedélyekkel
-
PAT-hitelesítési hibák: Ellenőrizze, hogy a jogkivonat érvényes-e, és megfelelő hatókörrel rendelkezik-e (
vso.worka munkaelem-hozzáféréshez) - Jogkivonat lejárata: Ellenőrizze, hogy a PAT lejárt-e, és szükség esetén hozzon létre egy újat
Lekérdezéssel kapcsolatos problémák
- Érvénytelen WIQL-szintaxis: Győződjön meg arról, hogy a munkaelem lekérdezési nyelvének szintaxisa helyes
- Projektnévvel kapcsolatos hibák: Ellenőrizze, hogy létezik-e a projekt neve, és helyesen van-e beírva
-
Mezőnévvel kapcsolatos hibák: Használja a megfelelő rendszermezőneveket (például
System.Id,System.Title)
Gyakori kivételek
- VssUnauthorizedException: Hitelesítési adatok és engedélyek ellenőrzése
- ArgumentException: Ellenőrizze, hogy az összes szükséges paraméter meg van-e adva és érvényes-e
- HttpRequestException: A hálózati kapcsolat és a szolgáltatás rendelkezésre állásának ellenőrzése
Teljesítménnyel kapcsolatos problémák
- Lassú lekérdezések: Adjon hozzá megfelelő WHERE záradékokat és korlátozza az eredményhalmazokat
- Memóriahasználat: Nagy eredményhalmazok feldolgozása kötegekben
- Sebességkorlátozás: Újrapróbálkozási logika implementálása exponenciális visszalépéssel