Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Azure DevOps Services | Azure DevOps Server | Azure DevOps Server 2022
Avertissement
Technologie héritée - alternatives modernes recommandées
Ces clients BASÉS sur SOAP sont des technologies héritées et doivent être utilisés uniquement pour :
- Gestion des applications existantes qui ne peuvent pas être modernisées
- Applications .NET Framework qui nécessitent des fonctionnalités spécifiques à SOAP
Pour le nouveau développement, utilisez les bibliothèques de client .NET modernes basées sur REST qui offrent :
- ✅ Meilleures performances et fiabilité
- ✅ Prise en charge de .NET Core, .NET 5+ et .NET Framework
- ✅ Méthodes d’authentification modernes (identités managées, principaux de service)
- ✅ Modèles Async/await et fonctionnalités C# modernes
- ✅ Développement et support actifs
Cet article contient des exemples d’intégration avec Azure DevOps Server et Azure DevOps Services à l’aide de clients SOAP hérités. Ces clients sont disponibles uniquement dans la version du .NET Framework et nécessitent des méthodes d’authentification locales ou héritées.
Conditions préalables et limitations
Exigences:
- .NET Framework 4.6.1 ou version ultérieure
- Packages NuGet obsolètes
- Environnement Windows pour la prise en charge du client SOAP
Limitations :
- ❌ Aucune prise en charge de .NET Core ou .NET 5+
- ❌ Options d’authentification modernes limitées
- ❌ Aucun modèle asynchrone/await
- ❌ Réduction des performances par rapport aux clients REST
- ❌ Prise en charge et mises à jour ultérieures limitées
Packages NuGet requis :
- Microsoft.TeamFoundationServer.ExtendedClient - Clients SOAP anciens
- Microsoft.TeamFoundationServer.Client - API Azure DevOps principales
- Microsoft.VisualStudio.Services.Client - Connexion et authentification
- Microsoft.VisualStudio.Services.InteractiveClient - Flux d’authentification interactifs
Conseils sur la migration
Chemin de migration recommandé
Étape 1 : Évaluer votre utilisation actuelle
- Identifier les fonctionnalités spécifiques à SOAP que votre application utilise
- Déterminer si des API REST équivalentes sont disponibles
- Évaluer les exigences d’authentification
Étape 2 : Planifier la stratégie de migration
- Immédiat : Mettre à jour l’authentification pour utiliser des PAT ou Microsoft Entra ID
- Court terme : Migrer vers des clients BASÉS sur REST tout en conservant .NET Framework
- Long terme : Moderniser vers .NET Core/.NET 5+ avec les clients REST
Étape 3 : Implémenter la migration
- Commencez par les mises à jour d’authentification. Consultez les exemples suivants.
- Remplacer les clients SOAP par des équivalents REST de manière incrémentielle
- Tester soigneusement avant le déploiement en production
Pour obtenir des instructions détaillées sur la migration, consultez les exemples de bibliothèque de client .NET.
Exemples de clients SOAP anciens
Utilisation de base du client SOAP
Importante
Cet exemple montre uniquement les modèles hérités pour référence. Utilisez des exemples BASÉS sur REST pour le nouveau développement.
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.VisualStudio.Services.Common;
using System;
using System.Linq;
/// <summary>
/// Legacy SOAP client example - use REST clients for new development
/// Creates a work item query, runs it, and displays results
/// </summary>
public static class LegacySoapExample
{
public static void ExecuteWorkItemQuery(string collectionUri, string teamProjectName, VssCredentials credentials)
{
try
{
// Create TfsTeamProjectCollection instance with credentials
using (var tpc = new TfsTeamProjectCollection(new Uri(collectionUri), credentials))
{
// Authenticate the connection
tpc.Authenticate();
// Get the WorkItemStore service (SOAP-based)
var workItemStore = tpc.GetService<WorkItemStore>();
// Get the project context
var workItemProject = workItemStore.Projects[teamProjectName];
// Find 'My Queries' folder
var myQueriesFolder = workItemProject.QueryHierarchy
.OfType<QueryFolder>()
.FirstOrDefault(qh => qh.IsPersonal);
if (myQueriesFolder != null)
{
const string queryName = "Legacy SOAP Sample";
// Check if query already exists
var existingQuery = myQueriesFolder
.OfType<QueryDefinition>()
.FirstOrDefault(qi => qi.Name.Equals(queryName, StringComparison.OrdinalIgnoreCase));
QueryDefinition queryDefinition;
if (existingQuery == null)
{
// Create new query with proper WIQL
queryDefinition = new QueryDefinition(
queryName,
@"SELECT [System.Id], [System.WorkItemType], [System.Title],
[System.AssignedTo], [System.State], [System.Tags]
FROM WorkItems
WHERE [System.TeamProject] = @project
AND [System.WorkItemType] = 'Bug'
AND [System.State] = 'New'
ORDER BY [System.CreatedDate] DESC");
myQueriesFolder.Add(queryDefinition);
workItemProject.QueryHierarchy.Save();
}
else
{
queryDefinition = existingQuery;
}
// Execute the query
var workItems = workItemStore.Query(queryDefinition.QueryText);
Console.WriteLine($"Found {workItems.Count} work items:");
foreach (WorkItem workItem in workItems)
{
var title = workItem.Fields["System.Title"].Value;
var state = workItem.Fields["System.State"].Value;
Console.WriteLine($"#{workItem.Id}: {title} [{state}]");
}
if (workItems.Count == 0)
{
Console.WriteLine("No work items found matching the query criteria.");
}
}
else
{
Console.WriteLine("'My Queries' folder not found.");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error executing SOAP query: {ex.Message}");
throw;
}
}
}
Méthodes d’authentification héritées
Avertissement
Ces méthodes d’authentification présentent des limitations de sécurité. Migrez vers l’authentification moderne lorsque cela est possible.
Authentification par jeton d’accès personnel (non recommandée)
/// <summary>
/// Authenticate SOAP client using Personal Access Token
/// Most secure option for legacy SOAP clients
/// </summary>
public static void AuthenticateWithPAT(string collectionUri, string personalAccessToken)
{
try
{
var credentials = new VssBasicCredential(string.Empty, personalAccessToken);
using (var tpc = new TfsTeamProjectCollection(new Uri(collectionUri), credentials))
{
tpc.Authenticate();
Console.WriteLine($"Successfully authenticated to: {tpc.DisplayName}");
Console.WriteLine($"Instance ID: {tpc.InstanceId}");
}
}
catch (Exception ex)
{
Console.WriteLine($"PAT authentication failed: {ex.Message}");
throw;
}
}
Authentification Microsoft Entra (support limité)
/// <summary>
/// Microsoft Entra authentication for SOAP services
/// Limited to specific scenarios - prefer REST clients for modern auth
/// </summary>
public static void AuthenticateWithEntraID(string collectionUri)
{
try
{
// Note: Limited authentication options compared to REST clients
var credentials = new VssAadCredential();
using (var tpc = new TfsTeamProjectCollection(new Uri(collectionUri), credentials))
{
tpc.Authenticate();
Console.WriteLine($"Successfully authenticated with Microsoft Entra ID");
Console.WriteLine($"Collection: {tpc.DisplayName}");
}
}
catch (Exception ex)
{
Console.WriteLine($"Microsoft Entra authentication failed: {ex.Message}");
Console.WriteLine("Consider migrating to REST clients for better authentication support.");
throw;
}
}
Authentification interactive (.NET Framework uniquement)
/// <summary>
/// Interactive authentication with Visual Studio sign-in prompt
/// Only works in .NET Framework with UI context
/// </summary>
public static void AuthenticateInteractively(string collectionUri)
{
try
{
var credentials = new VssClientCredentials();
using (var tpc = new TfsTeamProjectCollection(new Uri(collectionUri), credentials))
{
tpc.Authenticate();
Console.WriteLine($"Interactive authentication successful");
Console.WriteLine($"Authenticated user: {tpc.AuthorizedIdentity.DisplayName}");
}
}
catch (Exception ex)
{
Console.WriteLine($"Interactive authentication failed: {ex.Message}");
Console.WriteLine("Ensure application has UI context and user interaction is possible.");
throw;
}
}
Authentification par nom d’utilisateur/mot de passe (déconseillée)
Avertissement
L’authentification par nom d’utilisateur/mot de passe est déconseillée et non sécurisée. Utilisez plutôt des paTs ou des méthodes d’authentification modernes.
/// <summary>
/// Username/password authentication - DEPRECATED AND INSECURE
/// Only use for legacy on-premises scenarios where no alternatives exist
/// </summary>
[Obsolete("Username/password authentication is deprecated. Use PATs or modern authentication.")]
public static void AuthenticateWithUsernamePassword(string collectionUri, string username, string password)
{
try
{
var credentials = new VssAadCredential(username, password);
using (var tpc = new TfsTeamProjectCollection(new Uri(collectionUri), credentials))
{
tpc.Authenticate();
Console.WriteLine("Username/password authentication successful (DEPRECATED)");
}
}
catch (Exception ex)
{
Console.WriteLine($"Username/password authentication failed: {ex.Message}");
Console.WriteLine("This method is deprecated. Please migrate to PATs or modern authentication.");
throw;
}
}
Exemple complet hérité
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.VisualStudio.Services.Common;
using System;
using System.Configuration;
/// <summary>
/// Complete example showing legacy SOAP client usage
/// For reference only - use REST clients for new development
/// </summary>
class LegacySoapProgram
{
static void Main(string[] args)
{
try
{
// Get configuration (prefer environment variables or secure config)
var collectionUri = ConfigurationManager.AppSettings["CollectionUri"];
var projectName = ConfigurationManager.AppSettings["ProjectName"];
var personalAccessToken = ConfigurationManager.AppSettings["PAT"]; // Store securely
if (string.IsNullOrEmpty(collectionUri) || string.IsNullOrEmpty(projectName))
{
Console.WriteLine("Please configure CollectionUri and ProjectName in app.config");
return;
}
Console.WriteLine("=== Legacy SOAP Client Example ===");
Console.WriteLine("WARNING: This uses deprecated SOAP clients.");
Console.WriteLine("Consider migrating to REST clients for better performance and support.");
Console.WriteLine();
VssCredentials credentials;
if (!string.IsNullOrEmpty(personalAccessToken))
{
// Recommended: Use PAT authentication
credentials = new VssBasicCredential(string.Empty, personalAccessToken);
Console.WriteLine("Using Personal Access Token authentication");
}
else
{
// Fallback: Interactive authentication (requires UI)
credentials = new VssClientCredentials();
Console.WriteLine("Using interactive authentication");
}
// Execute the legacy SOAP example
LegacySoapExample.ExecuteWorkItemQuery(collectionUri, projectName, credentials);
Console.WriteLine();
Console.WriteLine("Example completed successfully.");
Console.WriteLine("For new development, see: https://docs.microsoft.com/azure/devops/integrate/concepts/dotnet-client-libraries");
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
Console.WriteLine();
Console.WriteLine("Migration recommendations:");
Console.WriteLine("1. Update to REST-based client libraries");
Console.WriteLine("2. Use modern authentication (managed identities, service principals)");
Console.WriteLine("3. Migrate to .NET Core/.NET 5+ for better performance");
Environment.Exit(1);
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
}
Migration vers des clients modernes
Comparaison côte à côte
Approche SOAP héritée :
// ❌ Legacy SOAP pattern
using (var tpc = new TfsTeamProjectCollection(uri, credentials))
{
var workItemStore = tpc.GetService<WorkItemStore>();
var workItems = workItemStore.Query("SELECT * FROM WorkItems");
// Synchronous, blocking operations
}
Approche REST moderne :
// ✅ Modern REST pattern
using var connection = new VssConnection(uri, credentials);
var witClient = connection.GetClient<WorkItemTrackingHttpClient>();
var workItems = await witClient.QueryByWiqlAsync(new Wiql { Query = "SELECT * FROM WorkItems" });
// Asynchronous, non-blocking operations
Principales différences
| Caractéristique | SOAP hérité | REST moderne |
|---|---|---|
| Support de plateforme | .NET Framework uniquement | .NET Framework, .NET Core, .NET 5+ |
| Niveau de performance | Plus lent, synchrone | Plus rapide, asynchrone |
| Authentification | Options limitées | Assistance complète pour l'authentification moderne |
| Couverture des API | API héritées uniquement | Couverture complète de l’API REST |
| Assistance future | Maintenance uniquement | Développement actif |
| Modèles de code | Blocage synchrone | Modèles Async/await |
Résolution des problèmes liés aux anciens clients
Problèmes courants et solutions
Échecs d’authentification :
- Vérifier que les PAT ont des étendues appropriées
- Vérifier le format de l’URL de l’organisation (inclure la collection pour les éléments locaux)
- Vérifier les paramètres de pare-feu et de proxy pour les points de terminaison SOAP
Problèmes de performances :
- Les clients SOAP sont intrinsèquement plus lents que REST
- Prendre en compte les opérations de traitement par lots lorsque cela est possible
- Migrer vers des clients REST pour améliorer les performances
Compatibilité de la plateforme :
- Les clients SOAP fonctionnent uniquement sur .NET Framework
- Utiliser des clients REST pour la prise en charge multiplateforme
Obtenir de l’aide
Pour les problèmes liés aux anciens clients SOAP :
- Vérifier la communauté des développeurs Azure DevOps
- Passer en revue les conseils de migration pour les alternatives modernes
- Prendre en compte les services de migration professionnels pour les applications volumineuses
Ressources associées
Ressources de migration :
- Exemples de bibliothèques de client .NET modernes - Remplacement recommandé
- Conseils d’authentification - Options d’authentification modernes
- Informations de référence sur l’API REST Azure DevOps - Documentation complète sur l’API
Documentation héritée :
Importante
Planification de la migration ? Commencez par des exemples de bibliothèques clientes .NET modernes pour voir les meilleures pratiques et les options d’authentification actuelles.