Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Azure DevOps Services | Azure DevOps Server | Azure DevOps Server 2022
Avvertimento
Tecnologia obsoleta - alternative moderne consigliate
Questi client basati su SOAP sono tecnologie legacy e devono essere usati solo per:
- Gestione di applicazioni esistenti che non possono essere modernizzate
- Applicazioni .NET Framework che richiedono funzionalità specifiche di SOAP
Per il nuovo sviluppo, usare le moderne librerie client .NET basate su REST che offrono:
- ✅ Prestazioni e affidabilità migliori
- ✅ Supporto per .NET Core, .NET 5+e .NET Framework
- ✅ Metodi di autenticazione moderni (identità gestite, principali del servizio)
- ✅ Pattern async/await e funzionalità moderne di C#
- ✅ Sviluppo e supporto attivi
Questo articolo contiene esempi per l'integrazione con Azure DevOps Server e Azure DevOps Services usando client SOAP legacy. Questi client sono disponibili solo nella versione di .NET Framework e richiedono metodi di autenticazione locali o legacy.
Prerequisiti e limitazioni
Requirements:
- .NET Framework 4.6.1 o versioni successive
- Pacchetti NuGet obsoleti
- Ambiente Windows per il supporto client SOAP
Limitazioni:
- ❌ Nessun supporto per .NET Core o .NET 5+
- ❌ Opzioni di autenticazione moderne limitate
- ❌ Nessun modello async/await
- ❌ Prestazioni ridotte rispetto ai client REST
- ❌ Supporto e aggiornamenti futuri limitati
Pacchetti NuGet necessari:
- Microsoft.TeamFoundationServer.ExtendedClient - Clienti SOAP legacy
- Microsoft.TeamFoundationServer.Client - API Di Base di Azure DevOps
- Microsoft.VisualStudio.Services.Client - Connessione e autenticazione
- Microsoft.VisualStudio.Services.InteractiveClient - Flussi di autenticazione interattivi
Indicazioni sulla migrazione
Percorso di migrazione consigliato
Passaggio 1: Valutare l'utilizzo corrente
- Identificare le funzionalità specifiche di SOAP usate dall'applicazione
- Determinare se sono disponibili API REST equivalenti
- Valutare i requisiti di autenticazione
Passaggio 2: Pianificare la strategia di migrazione
- Immediato: aggiornare l'autenticazione per l'uso di PAT o ID Microsoft Entra
- A breve termine: eseguire la migrazione a client basati su REST mantenendo .NET Framework
- A lungo termine: modernizzare a .NET Core/.NET 5+ con client REST
Passaggio 3: Implementare la migrazione
- Iniziare con gli aggiornamenti dell'autenticazione. Vedere gli esempi seguenti.
- Sostituire i client SOAP con equivalenti REST in modo incrementale
- Testare accuratamente prima della distribuzione nell'ambiente di produzione
Per indicazioni dettagliate sulla migrazione, vedere esempi di librerie client .NET.
Esempi di client SOAP legacy
Utilizzo del client SOAP di base
Importante
In questo esempio vengono illustrati modelli legacy solo per riferimento. Usare esempi basati su REST per il nuovo sviluppo.
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;
}
}
}
Metodi di autenticazione legacy
Avvertimento
Questi metodi di autenticazione presentano limitazioni di sicurezza. Eseguire la migrazione all'autenticazione moderna , quando possibile.
Autenticazione del token di accesso personale (scelta non consigliata)
/// <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;
}
}
Autenticazione Di Microsoft Entra (supporto limitato)
/// <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;
}
}
Autenticazione interattiva (solo .NET Framework)
/// <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;
}
}
Autenticazione con nome utente/password (deprecato)
Attenzione
L'autenticazione con nome utente/password è deprecata e non sicura. Utilizzare piuttosto i PATs o metodi di autenticazione moderni.
/// <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;
}
}
Esempio legacy completo
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();
}
}
Migrazione ai client moderni
Confronto fianco a fianco
Approccio SOAP precedente:
// ❌ 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
}
Approccio REST moderno:
// ✅ 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
Differenze principali
| Caratteristica / Funzionalità | Legacy SOAP | REST moderno |
|---|---|---|
| Supporto della piattaforma | Esclusivamente .NET Framework | .NET Framework, .NET Core, .NET 5+ |
| Prestazioni | Più lento, sincrono | Più veloce, asincrono |
| Autenticazione | Opzioni limitate | Supporto completo dell'autenticazione moderna |
| Copertura API | Solo API storici | Copertura completa dell'API REST |
| Supporto futuro | Solo manutenzione | Sviluppo attivo |
| Modelli di codice | Blocco sincrono | Modelli di async/await |
Risoluzione dei problemi dei client legacy
Problemi e soluzioni comuni
Errori di autenticazione:
- Assicurarsi che i PAT dispongano di ambiti appropriati
- Verificare il formato dell'URL dell'organizzazione (includere la raccolta per l'ambiente locale)
- Controllare le impostazioni del firewall e del proxy per gli endpoint SOAP
Problemi di prestazioni:
- I client SOAP sono intrinsecamente più lenti rispetto a REST
- Prendere in considerazione le operazioni batch laddove possibile
- Eseguire la migrazione ai client REST per ottenere prestazioni migliori
Compatibilità della piattaforma:
- I client SOAP funzionano solo in .NET Framework
- Usare i client REST per il supporto multipiattaforma
Ottenere assistenza
In caso di problemi con il client SOAP legacy:
- Controllare la community degli sviluppatori di Azure DevOps
- Esaminare le linee guida sulla migrazione per le alternative moderne
- Prendere in considerazione i servizi di migrazione professionale per applicazioni di grandi dimensioni
" output is necessary.)
Risorse di migrazione:
- Esempi di librerie client .NET moderne - Sostituzione consigliata
- Linee guida per l'autenticazione - Opzioni di autenticazione moderne
- Informazioni di riferimento sulle API REST di Azure DevOps - Documentazione completa dell'API
Documentazione legacy:
Importante
Pianificazione della migrazione? Iniziare con gli esempi moderni di libreria client .NET per visualizzare le procedure consigliate e le opzioni di autenticazione correnti.