Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Azure DevOps Services | Azure DevOps Server | Azure DevOps Server 2022
Advertencia
Tecnología heredada: alternativas modernas recomendadas
Estos clientes basados en SOAP son tecnología heredada y solo se deben usar para:
- Mantenimiento de aplicaciones existentes que no se pueden modernizar
- Aplicaciones de .NET Framework que requieren funcionalidad específica de SOAP
Para el desarrollo nuevo, use las bibliotecas cliente de .NET modernas basadas en REST que ofrecen:
- ✅ Mejor rendimiento y confiabilidad
- ✅ Compatibilidad con .NET Core, .NET 5 y .NET Framework
- ✅ Métodos de autenticación modernos (identidades administradas, entidades de servicio)
- ✅ Patrones de async/await y funciones modernas de C#
- ✅ Desarrollo y soporte técnico activos
Este artículo contiene ejemplos para la integración con Azure DevOps Server y Azure DevOps Services mediante clientes SOAP heredados. Estos clientes solo están disponibles en la versión de .NET Framework y requieren métodos de autenticación locales o heredados.
Requisitos previos y limitaciones
Requisitos:
- .NET Framework 4.6.1 o versiones posteriores
- Paquetes NuGet antiguos
- Entorno de Windows para soporte de cliente SOAP
Limitaciones:
- ❌ No se admite .NET Core ni .NET 5+
- ❌ Opciones de autenticación moderna limitadas
- ❌ No hay patrones de async/await
- ❌ Rendimiento reducido en comparación con los clientes REST
- ❌ Compatibilidad y actualizaciones futuras limitadas
Paquetes NuGet necesarios:
- Microsoft.TeamFoundationServer.ExtendedClient : clientes SOAP heredados
- Microsoft.TeamFoundationServer.Client : API básicas de Azure DevOps
- Microsoft.VisualStudio.Services.Client : conexión y autenticación
- Microsoft.VisualStudio.Services.InteractiveClient : flujos de autenticación interactivos
Guía de migración
Ruta de migración recomendada
Paso 1: Evaluación del uso actual
- Identificación de la funcionalidad específica de SOAP que usa la aplicación
- Determinar si las API REST equivalentes están disponibles
- Evaluación de los requisitos de autenticación
Paso 2: Planear la estrategia de migración
- Inmediato: actualización de la autenticación para usar PAT o Microsoft Entra ID
- A corto plazo: Migración a clientes basados en REST al tiempo que mantiene .NET Framework
- A largo plazo: modernización a .NET Core/.NET 5+ con clientes REST
Paso 3: Implementar la migración
- Comience con las actualizaciones de autenticación. Consulte los ejemplos siguientes.
- Reemplazar clientes SOAP por equivalentes REST incrementalmente
- Prueba exhaustiva antes de realizar la implementación en producción
Para obtener instrucciones detalladas sobre la migración, consulte ejemplos de biblioteca cliente de .NET.
Ejemplos de clientes SOAP heredados
Uso básico del cliente SOAP
Importante
En este ejemplo se muestran los patrones heredados solo para referencia. Utiliza ejemplos que utilicen REST para el nuevo desarrollo.
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étodos de autenticación heredados
Advertencia
Estos métodos de autenticación tienen limitaciones de seguridad. Migre a la autenticación moderna siempre que sea posible.
Autenticación de token de acceso personal (no recomendado)
/// <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;
}
}
Autenticación de Microsoft Entra (compatibilidad limitada)
/// <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;
}
}
Autenticación interactiva (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;
}
}
Autenticación de nombre de usuario y contraseña (en desuso)
Precaución
La autenticación de nombre de usuario y contraseña está en desuso y no es segura. En su lugar, use PAT o métodos de autenticación modernos.
/// <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;
}
}
Ejemplo heredado 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();
}
}
Migración a clientes de software modernos
Comparación en paralelo
Enfoque SOAP heredado:
// ❌ 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
}
Enfoque DE 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
Principales diferencias
| Característica | SOAP heredado | REST moderno |
|---|---|---|
| Compatibilidad con la plataforma | Solo para .NET Framework | .NET Framework, .NET Core, .NET 5+ |
| Rendimiento | Más lento, sincrónico | Más rápido, asincrónico |
| Autenticación | Opciones limitadas | Compatibilidad completa con la autenticación moderna |
| Cobertura de API | Solo API heredadas | Cobertura completa de la API REST |
| Soporte técnico futuro | Solo mantenimiento | Desarrollo activo |
| Patrones de código | Bloqueo sincrónico | Patrones asincrónicos y await |
Solución de problemas de clientes heredados
Problemas comunes y soluciones
Errores de autenticación:
- Asegurarse de que los PAT tienen ámbitos adecuados
- Comprobar el formato de dirección URL de la organización (incluir recopilación para el entorno local)
- Comprobación de la configuración de firewall y proxy para los puntos de conexión SOAP
Problemas de rendimiento:
- Los clientes SOAP son intrínsecamente más lentos que REST
- Considere las operaciones por lotes siempre que sea posible.
- Migración a clientes REST para mejorar el rendimiento
Compatibilidad de la plataforma:
- Los clientes SOAP solo funcionan en .NET Framework
- Uso de clientes REST para la compatibilidad multiplataforma
Obtener ayuda
Para cuestiones de clientes SOAP de versiones anteriores:
- Consulta la Comunidad de desarrolladores de Azure DevOps
- Revisión de la guía de migración para alternativas modernas
- Considere la posibilidad de servicios de migración profesionales para aplicaciones grandes
Recursos relacionados
Recursos de migración:
- Ejemplos modernos de biblioteca cliente de .NET : reemplazo recomendado
- Guía de autenticación : opciones de autenticación modernas
- Referencia de la API REST de Azure DevOps : documentación completa de la API
Documentación heredada:
Importante
¿Planeación de la migración? Comience con ejemplos modernos de biblioteca cliente de .NET para ver los procedimientos recomendados actuales y las opciones de autenticación.