Azure DevOps 服務 |Azure DevOps Server |Azure DevOps Server 2022
本文提供 Azure DevOps Services 的實際 REST API 範例。 這些範例示範一般作業,例如取得專案、管理工作項目,並使用 Microsoft Entra ID 的安全驗證模式。
這很重要
這些範例會使用 Microsoft Entra ID 驗證,這是生產應用程式的建議方法。 雖然個人存取令牌 (PAT) 可用於簡單的腳本,Microsoft Entra ID 提供更佳的安全性和治理功能。
驗證概觀
Azure DevOps REST API 支持數種驗證方法:
- Microsoft Entra 識別碼 - 建議用於生產應用程式(這些範例中使用)
- 個人存取令牌 (PAT) - 腳本和測試的簡單驗證
- OAuth 2.0 - 適用於第三方應用程式
- 服務主體 - 適用於自動化案例
這很重要
我們建議使用更安全的 Microsoft Entra 令牌,而非風險較高的 個人存取令牌。 深入了解我們減少 PAT 使用量的努力。 檢 閱我們的驗證指引 ,為您的需求選擇正確的驗證機制。
Microsoft Entra ID 驗證
針對Microsoft Entra ID 驗證,您必須註冊應用程式並取得存取令牌。 以下說明如何使用 Microsoft 驗證連結庫進行驗證 (MSAL):
首先,安裝必要的 NuGet 套件:
<PackageReference Include="Microsoft.Identity.Client" Version="4.61.3" />
using Microsoft.Identity.Client;
using System.Net.Http.Headers;
public async Task<string> GetAccessTokenAsync()
{
var app = PublicClientApplicationBuilder
.Create("{your-client-id}")
.WithAuthority("https://login.microsoftonline.com/{your-tenant-id}")
.WithRedirectUri("http://localhost")
.Build();
var scopes = new[] { "https://app.vssps.visualstudio.com/.default" };
try
{
var result = await app.AcquireTokenInteractive(scopes).ExecuteAsync();
return result.AccessToken;
}
catch (MsalException ex)
{
Console.WriteLine($"Authentication failed: {ex.Message}");
throw;
}
}
REST API 範例
列出專案 (GET)
擷取貴組織中的所有專案:
C# 範例
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Microsoft.Identity.Client;
public async Task<string> GetProjectsAsync(string organization)
{
using var client = new HttpClient();
// Get Microsoft Entra ID access token
var entraIdAccessToken = await GetAccessTokenAsync();
// Set base address and headers
client.BaseAddress = new Uri($"https://dev.azure.com/{organization}/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// Add authentication header
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", entraIdAccessToken);
try
{
var response = await client.GetAsync("_apis/projects?api-version=7.2");
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
catch (HttpRequestException ex)
{
Console.WriteLine($"Request failed: {ex.Message}");
throw;
}
}
PowerShell 範例
# Install required module if not already installed
# Install-Module -Name MSAL.PS -Force
Import-Module MSAL.PS
$clientId = "your-client-id"
$tenantId = "your-tenant-id"
$organization = "your-organization"
# Get access token
$token = Get-MsalToken -ClientId $clientId -TenantId $tenantId -Scopes "https://app.vssps.visualstudio.com/.default"
$headers = @{
'Authorization' = "Bearer $($token.AccessToken)"
'Accept' = 'application/json'
}
$uri = "https://dev.azure.com/$organization/_apis/projects?api-version=7.2"
try {
$response = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers
Write-Host "Retrieved $($response.count) projects"
$response.value | ForEach-Object { Write-Host "- $($_.name)" }
}
catch {
Write-Error "Failed to retrieve projects: $($_.Exception.Message)"
}
建立工作項目(POST)
在您的專案建立新的工作專案:
C# 範例
using System.Text;
using Newtonsoft.Json;
public async Task<string> CreateWorkItemAsync(string organization, string project)
{
using var client = new HttpClient();
// Get Microsoft Entra ID access token
var entraIdAccessToken = await GetAccessTokenAsync();
// Set base address and headers
client.BaseAddress = new Uri($"https://dev.azure.com/{organization}/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", entraIdAccessToken);
var workItem = new
{
fields = new
{
SystemTitle = "Sample work item",
SystemDescription = "Created via REST API with Microsoft Entra ID",
SystemTags = "api; sample; entra-id"
}
};
var json = JsonConvert.SerializeObject(workItem);
var content = new StringContent(json, Encoding.UTF8, "application/json");
try
{
var response = await client.PostAsync($"{project}/_apis/wit/workitems/$Task?api-version=7.2", content);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
catch (HttpRequestException ex)
{
Console.WriteLine($"Request failed: {ex.Message}");
throw;
}
}
PowerShell 範例
Import-Module MSAL.PS
$clientId = "your-client-id"
$tenantId = "your-tenant-id"
$organization = "your-organization"
$project = "your-project"
# Get access token
$token = Get-MsalToken -ClientId $clientId -TenantId $tenantId -Scopes "https://app.vssps.visualstudio.com/.default"
$headers = @{
'Authorization' = "Bearer $($token.AccessToken)"
'Content-Type' = 'application/json'
}
$body = @{
fields = @{
'System.Title' = 'Sample work item'
'System.Description' = 'Created via REST API with Microsoft Entra ID'
'System.Tags' = 'api; sample; entra-id'
}
} | ConvertTo-Json
$uri = "https://dev.azure.com/$organization/$project/_apis/wit/workitems/`$Task?api-version=7.2"
try {
$response = Invoke-RestMethod -Uri $uri -Method Post -Headers $headers -Body $body
Write-Host "Work item created with ID: $($response.id)"
}
catch {
Write-Error "Failed to create work item: $($_.Exception.Message)"
}
更新工作項目(修補)
更新現有工作項目的狀態:
C# 範例
using System.Text;
using Newtonsoft.Json;
public async Task<string> UpdateWorkItemAsync(string organization, string project, int workItemId)
{
using var client = new HttpClient();
// Get Microsoft Entra ID access token
var entraIdAccessToken = await GetAccessTokenAsync();
// Set base address and headers
client.BaseAddress = new Uri($"https://dev.azure.com/{organization}/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", entraIdAccessToken);
var patchOperations = new[]
{
new
{
op = "add",
path = "/fields/System.State",
value = "In Progress"
},
new
{
op = "add",
path = "/fields/System.AssignedTo",
value = "user@example.com"
}
};
var json = JsonConvert.SerializeObject(patchOperations);
var content = new StringContent(json, Encoding.UTF8, "application/json-patch+json");
try
{
var response = await client.PatchAsync($"{project}/_apis/wit/workitems/{workItemId}?api-version=7.2", content);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
catch (HttpRequestException ex)
{
Console.WriteLine($"Request failed: {ex.Message}");
throw;
}
}
PowerShell 範例
Import-Module MSAL.PS
$clientId = "your-client-id"
$tenantId = "your-tenant-id"
$organization = "your-organization"
$project = "your-project"
$workItemId = 123 # Replace with actual work item ID
# Get access token
$token = Get-MsalToken -ClientId $clientId -TenantId $tenantId -Scopes "https://app.vssps.visualstudio.com/.default"
$headers = @{
'Authorization' = "Bearer $($token.AccessToken)"
'Content-Type' = 'application/json-patch+json'
}
$body = @(
@{
op = "add"
path = "/fields/System.State"
value = "In Progress"
},
@{
op = "add"
path = "/fields/System.AssignedTo"
value = "user@example.com"
}
) | ConvertTo-Json
$uri = "https://dev.azure.com/$organization/$project/_apis/wit/workitems/$workItemId?api-version=7.2"
try {
$response = Invoke-RestMethod -Uri $uri -Method Patch -Headers $headers -Body $body
Write-Host "Work item $workItemId updated successfully"
}
catch {
Write-Error "Failed to update work item: $($_.Exception.Message)"
}
移除工作專案 (DELETE)
從您的專案中移除工作項目:
C# 範例
public async Task<bool> DeleteWorkItemAsync(string organization, string project, int workItemId)
{
using var client = new HttpClient();
// Get Microsoft Entra ID access token
var entraIdAccessToken = await GetAccessTokenAsync();
// Set base address and headers
client.BaseAddress = new Uri($"https://dev.azure.com/{organization}/");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", entraIdAccessToken);
try
{
var response = await client.DeleteAsync($"{project}/_apis/wit/workitems/{workItemId}?api-version=7.2");
response.EnsureSuccessStatusCode();
Console.WriteLine($"Work item {workItemId} deleted successfully");
return true;
}
catch (HttpRequestException ex)
{
Console.WriteLine($"Request failed: {ex.Message}");
throw;
}
}
.NET 用戶端程式庫
針對 .NET 應用程式,請使用 Azure DevOps .NET 用戶端連結庫,以取得更佳的類型安全性和更容易的開發。
安裝
將這些 NuGet 套件新增至您的專案:
<PackageReference Include="Microsoft.TeamFoundationServer.Client" Version="19.225.1" />
<PackageReference Include="Microsoft.VisualStudio.Services.Client" Version="19.225.1" />
<PackageReference Include="Microsoft.Identity.Client" Version="4.61.3" />
使用 .NET 用戶端取得專案
using Microsoft.TeamFoundation.Core.WebApi;
using Microsoft.VisualStudio.Services.Common;
using Microsoft.VisualStudio.Services.WebApi;
using Microsoft.Identity.Client;
public async Task<IEnumerable<TeamProjectReference>> GetProjectsAsync(string organizationUrl)
{
var uri = new Uri(organizationUrl);
// Get Microsoft Entra ID access token
var entraIdAccessToken = await GetAccessTokenAsync();
var credentials = new VssOAuthAccessTokenCredential(entraIdAccessToken);
using var connection = new VssConnection(uri, credentials);
using var projectClient = connection.GetClient<ProjectHttpClient>();
try
{
var projects = await projectClient.GetProjects();
return projects;
}
catch (Exception ex)
{
Console.WriteLine($"Error retrieving projects: {ex.Message}");
throw;
}
}
使用 .NET 用戶端建立工作專案
using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;
using Microsoft.VisualStudio.Services.WebApi.Patch;
using Microsoft.VisualStudio.Services.WebApi.Patch.Json;
using Microsoft.Identity.Client;
public async Task<WorkItem> CreateWorkItemAsync(string organizationUrl, string project)
{
var uri = new Uri(organizationUrl);
// Get Microsoft Entra ID access token
var entraIdAccessToken = await GetAccessTokenAsync();
var credentials = new VssOAuthAccessTokenCredential(entraIdAccessToken);
using var connection = new VssConnection(uri, credentials);
using var witClient = connection.GetClient<WorkItemTrackingHttpClient>();
var patchDocument = new JsonPatchDocument
{
new JsonPatchOperation
{
Operation = Operation.Add,
Path = "/fields/System.Title",
Value = "Sample work item created via .NET client with Microsoft Entra ID"
},
new JsonPatchOperation
{
Operation = Operation.Add,
Path = "/fields/System.Description",
Value = "This work item was created using the Azure DevOps .NET client library with Microsoft Entra ID authentication"
}
};
try
{
var workItem = await witClient.CreateWorkItemAsync(patchDocument, project, "Task");
return workItem;
}
catch (Exception ex)
{
Console.WriteLine($"Error creating work item: {ex.Message}");
throw;
}
}
錯誤處理
一律在您的應用程式中實作適當的錯誤處理:
try
{
var response = await client.GetAsync(requestUri);
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
// Process successful response
}
catch (HttpRequestException ex)
{
// Handle HTTP-related errors
Console.WriteLine($"HTTP Error: {ex.Message}");
}
catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException)
{
// Handle timeout
Console.WriteLine("Request timed out");
}
catch (Exception ex)
{
// Handle other errors
Console.WriteLine($"Unexpected error: {ex.Message}");
}
最佳做法
- 使用 Microsoft Entra ID:在生產應用程式中優先選用 Microsoft Entra ID 身份驗證,而不是 PAT (個人存取權杖) 驗證
- 使用 HTTPS:一律針對 API 呼叫使用安全連線
- 處理速率限制:使用指數退避實作重試邏輯
- 快取回應:儲存經常存取的數據以減少 API 呼叫
- 使用特定 API 版本:釘選至特定版本以避免重大變更
- 驗證輸入:在進行 API 呼叫之前,請一律驗證用戶輸入
- 適當記錄:記錄 API 互動以進行偵錯,但絕不會記錄認證
- 令牌管理:針對 Microsoft Entra ID 令牌實施適當的令牌快取和刷新邏輯