Примеры клиентской библиотеки SOAP для Azure DevOps

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

Предупреждение

Устаревшая технология — современные альтернативные варианты, рекомендуемые

Эти клиенты на основе SOAP являются устаревшими технологиями и должны использоваться только для:

  • Обслуживание существующих приложений, которые нельзя модернизировать
  • Приложения .NET Framework, требующие функциональных возможностей, относящихся к SOAP

Для новой разработки используйте современные клиентские библиотеки .NET на основе REST , которые предлагают:

  • ✅ Повышение производительности и надежности
  • ✅ Поддержка .NET Core, .NET 5+ и .NET Framework
  • ✅ Современные методы аутентификации (управляемые удостоверения, служебные главные компоненты)
  • ✅ Асинхронные и ожидаемые шаблоны и современные возможности C#
  • ✅ Активная разработка и поддержка

В этой статье содержатся примеры интеграции с Azure DevOps Server и Azure DevOps Services с использованием устаревших клиентов SOAP. Эти клиенты доступны только в версии .NET Framework и требуют локальных или устаревших методов проверки подлинности.

Предварительные требования и ограничения

Требования:

  • .NET Framework 4.6.1 или более поздней версии
  • Устаревшие пакеты NuGet
  • Среда Windows для поддержки клиентов SOAP

Ограничения:

  • ❌ Нет поддержки .NET Core или .NET 5+
  • ❌ Ограниченные современные параметры проверки подлинности
  • ❌ Нет асинхронных и ожидаемых шаблонов
  • ❌ Снижение производительности по сравнению с клиентами REST
  • ❌ Ограниченная будущая поддержка и обновления

Обязательные пакеты NuGet:

Руководство по миграции

Шаг 1. Оценка текущего использования

  • Определение функциональных возможностей, относящихся к SOAP, которые использует приложение
  • Определите, доступны ли эквивалентные REST API
  • Оценка требований к проверке подлинности

Шаг 2. Планирование стратегии миграции

  • Немедленно. Обновление проверки подлинности для использования идентификатора Microsoft Entra
  • Кратковременная миграция на клиенты на основе REST при сохранении платформы .NET Framework
  • Долгосрочное: модернизация до .NET Core/.NET 5+ с помощью клиентов REST

Шаг 3. Реализация миграции

  • Начните с обновлений аутентификации. Ознакомьтесь с приведенными ниже примерами.
  • Постепенно замените клиенты SOAP эквивалентами REST
  • Тщательно протестируйте перед развертыванием в рабочей среде

Подробные рекомендации по миграции см. в примерах клиентской библиотеки .NET.

Устаревшие примеры клиента SOAP

Базовое использование клиента SOAP

Это важно

В этом примере показаны устаревшие шаблоны только для ссылок. Используйте примеры на основе REST для новой разработки.

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

Устаревшие методы проверки подлинности

Предупреждение

Эти методы проверки подлинности имеют ограничения безопасности. Перейдите на современную проверку подлинности при возможности.

Это важно

Рассмотрите возможность использования более безопасных маркеров Microsoft Entra по сравнению с более высоким уровнем риска персональных маркеров доступа. Дополнительные сведения см. в разделе "Сокращение использования PAT". Просмотрите рекомендации по проверке подлинности , чтобы выбрать правильный механизм проверки подлинности для ваших потребностей.

Если необходимо использовать PAT, см. раздел «Использование личных маркеров доступа» для их создания. Затем передайте его в виде VssBasicCredential:

var credentials = new VssBasicCredential(string.Empty, personalAccessToken);

using (var tpc = new TfsTeamProjectCollection(new Uri(collectionUri), credentials))
{
    tpc.Authenticate();
}

Проверка подлинности Microsoft Entra (ограниченная поддержка)

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

Интерактивная проверка подлинности (только для .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;
    }
}

Проверка подлинности имени пользователя и пароля (не рекомендуется)

Осторожность

Проверка подлинности имени пользователя и пароля устарела и небезопасна. Вместо этого используйте современные методы проверки подлинности.

/// <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 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. Migrate to modern authentication.");
        throw;
    }
}

Полный пример устаревшей системы

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))
            {
                // Use PAT authentication (consider migrating to modern auth)
                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();
    }
}

Миграция на современные клиентские приложения

Параллельное сравнение

Устаревший подход 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
}

Современный подход 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

Основные отличия

Функция Устаревшая версия SOAP Современный REST
Поддержка платформы Только .NET Framework .NET Framework, .NET Core, .NET 5+
Производительность Медленнее, синхронно Быстрее, асинхронно
Аутентификация Ограниченные параметры Полная современная поддержка проверки подлинности
Покрытие API Только устаревшие API Полный охват REST API
Будущая поддержка Только обслуживание Активная разработка
Шаблоны кода Синхронная блокировка Асинхронные и ожидаемые шаблоны

Устранение неполадок устаревших клиентов

Распространенные проблемы и решения

Сбои проверки подлинности:

  • Убедитесь, что PATs имеют соответствующие области
  • Проверить формат URL организации (добавить коллекцию для локальной среды)
  • Проверка параметров брандмауэра и прокси-сервера для конечных точек SOAP

Проблемы с производительностью:

  • Клиенты SOAP по сути медленнее, чем REST
  • Рассмотрите возможность пакетных операций, когда это возможно
  • Миграция на клиенты REST для повышения производительности

Совместимость платформы:

  • Клиенты SOAP работают только в .NET Framework
  • Использование клиентов REST для кроссплатформенной поддержки

Получение помощи

Для устаревших проблем с клиентом SOAP:

  1. Ознакомьтесь с сообществом разработчиков Azure DevOps
  2. Ознакомьтесь с рекомендациями по миграции для современных альтернатив
  3. Рассмотрим профессиональные службы миграции для крупных приложений

Ресурсы миграции:

Устаревшая документация:

Это важно

Планирование миграции? Начните с современных примеров клиентской библиотеки .NET , чтобы просмотреть текущие рекомендации и параметры проверки подлинности.