Udostępnij przez


Przykłady biblioteki klienta protokołu SOAP dla usługi Azure DevOps

Azure DevOps Services | Azure DevOps Server | Azure DevOps Server 2022

Ostrzeżenie

Starsza technologia — zalecane nowoczesne alternatywy

Ci klienci oparty na protokole SOAP są starszą technologią i powinni być używane tylko w następujących celach:

  • Obsługa istniejących aplikacji, których nie można zmodernizować
  • Aplikacje .NET Framework, które wymagają funkcji specyficznych dla protokołu SOAP

W przypadku nowego programowania użyj nowoczesnych bibliotek klienckich platformy .NET opartych na protokole REST, które oferują:

  • ✅ Lepsza wydajność i niezawodność
  • ✅ Obsługa platform .NET Core, .NET 5+i .NET Framework
  • ✅ Nowoczesne metody uwierzytelniania (tożsamości zarządzane, jednostki usługi)
  • ✅ Wzorce async/await i nowoczesne funkcje języka C#
  • ✅ Aktywne programowanie i obsługa techniczna

Ten artykuł zawiera przykłady integracji z usługami Azure DevOps Server i Azure DevOps Services przy użyciu starszych klientów protokołu SOAP. Ci klienci są dostępni tylko w wersji programu .NET Framework i wymagają lokalnych lub starszych metod uwierzytelniania.

Wymagania wstępne i ograniczenia

Wymagania:

  • .NET Framework 4.6.1 lub nowszy
  • Starsze pakiety NuGet
  • Środowisko systemu Windows do obsługi klienta protokołu SOAP

Ograniczenia:

  • ❌ Brak obsługi platformy .NET Core lub .NET 5+
  • ❌ Ograniczone nowoczesne opcje uwierzytelniania
  • ❌ Brak wzorców async/await
  • ❌ Zmniejszona wydajność w porównaniu z klientami REST
  • ❌ Ograniczona pomoc techniczna i aktualizacje w przyszłości

Wymagane pakiety NuGet:

Wskazówki dotyczące migracji

Krok 1. Ocena bieżącego użycia

  • Identyfikowanie funkcji specyficznych dla protokołu SOAP używanych przez aplikację
  • Określanie, czy są dostępne równoważne interfejsy API REST
  • Ocena wymagań dotyczących uwierzytelniania

Krok 2. Planowanie strategii migracji

  • Natychmiastowe: aktualizowanie uwierzytelniania w celu używania numerów PAT lub identyfikatora Entra firmy Microsoft
  • Krótkoterminowa: migrowanie do klientów opartych na protokole REST przy zachowaniu programu .NET Framework
  • Długoterminowe: modernizacja platformy .NET Core/.NET 5+ przy użyciu klientów REST

Krok 3. Implementowanie migracji

  • Zacznij od aktualizacji uwierzytelniania. Zapoznaj się z poniższymi przykładami.
  • Zastąp klientów protokołu SOAP przyrostowo odpowiednikami REST
  • Dokładnie przetestuj przed wdrożeniem w środowisku produkcyjnym

Aby uzyskać szczegółowe wskazówki dotyczące migracji, zobacz Przykłady biblioteki klienta platformy .NET.

Przykłady starszych klientów protokołu SOAP

Podstawowe użycie klienta protokołu SOAP

Ważne

W tym przykładzie przedstawiono starsze wzorce tylko do celów referencyjnych. Użyj przykładów opartych na protokole REST na potrzeby nowego programowania.

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;
        }
    }
}

Starsze metody uwierzytelniania

Ostrzeżenie

Te metody uwierzytelniania mają ograniczenia zabezpieczeń. Migrowanie do nowoczesnego uwierzytelniania , jeśli jest to możliwe.

/// <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;
    }
}

Uwierzytelnianie Microsoft Entra (ograniczone wsparcie)

/// <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;
    }
}

Uwierzytelnianie interakcyjne (tylko platforma.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;
    }
}

Uwierzytelnianie za pomocą nazwy użytkownika/hasła (przestarzałe)

Ostrzeżenie

Uwierzytelnianie nazwy użytkownika/hasła jest przestarzałe i niezabezpieczone. Zamiast tego należy użyć sieci PAT lub nowoczesnych metod uwierzytelniania.

/// <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;
    }
}

Kompletny przykład dziedzictwa

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();
    }
}

Migracja do nowoczesnych klientów

Porównanie równoległe

Starsze podejście protokołu SOAP:

// ❌ 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
}

Nowoczesne podejście REST:

// ✅ 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

Kluczowe różnice

Funkcja Starsza wersja protokołu SOAP Nowoczesny interfejs REST
Obsługa platformy Tylko program .NET Framework .NET Framework, .NET Core, .NET 5+
Wydajność Wolniejsze, synchroniczne Szybsze, asynchroniczne
Authentication Ograniczone opcje Obsługa pełnego nowoczesnego uwierzytelniania
Zasięg interfejsu API Tylko starsze interfejsy API Pełne pokrycie interfejsu API REST
Pomoc techniczna w przyszłości Tylko konserwacja Aktywne programowanie
Wzorce kodu Blokowanie synchroniczne Wzorce async/await

Rozwiązywanie problemów ze starszymi klientami

Typowe problemy i rozwiązania

Błędy uwierzytelniania:

  • Upewnij się, że usługi PAT mają odpowiednie zakresy
  • Zweryfikuj format adresu URL organizacji (w tym kolekcję dla środowisk lokalnych)
  • Sprawdzanie ustawień zapory i serwera proxy dla punktów końcowych protokołu SOAP

Problemy z wydajnością:

  • Klienci protokołu SOAP są z natury wolniejsze niż REST
  • Rozważ operacje wsadowe tam, gdzie to możliwe
  • Migrowanie do klientów REST w celu uzyskania lepszej wydajności

Zgodność platformy:

  • Klienci protokołu SOAP działają tylko na platformie .NET Framework
  • Korzystanie z klientów REST na potrzeby obsługi wielu platform

Uzyskiwanie pomocy

W przypadku starszych problemów z klientem PROTOKOŁU SOAP:

  1. Sprawdź społeczność deweloperów usługi Azure DevOps
  2. Zapoznaj się ze wskazówkami dotyczącymi migracji dla nowoczesnych alternatyw
  3. Rozważ profesjonalne usługi migracji dla dużych aplikacji

Zasoby migracji:

Starsza dokumentacja:

Ważne

Planowanie migracji? Zacznij od nowoczesnych przykładów biblioteki klienta platformy .NET , aby zapoznać się z bieżącymi najlepszymi rozwiązaniami i opcjami uwierzytelniania.