Comprendiendo el error

El error “Communication with the underlying transaction manager has failed” ocurre cuando el servicio Microsoft Distributed Transaction Coordinator (MSDTC) en una máquina no puede comunicarse con el servicio MSDTC en otra máquina para coordinar una transacción distribuida.

El error completo y la excepción interna típicamente se ven así:

System.Transactions.TransactionManagerCommunicationException:
Communication with the underlying transaction manager has failed.

Inner Exception:
The MSDTC transaction manager was unable to pull the transaction from the
source transaction manager due to communication problems. Possible causes are:
a firewall is present and it doesn't have an exception for the MSDTC process,
the two machines cannot find each other by their NetBIOS names, or the support
for network transactions is not enabled for one of the two transaction managers.
(Exception from HRESULT: 0x8004D02B)

Esto ocurre comúnmente cuando:

  • Una aplicación .NET usa TransactionScope entre múltiples instancias de SQL Server
  • Un procedimiento almacenado usa servidores vinculados con BEGIN DISTRIBUTED TRANSACTION
  • Los servicios WCF usan enlaces transaccionales entre máquinas

Cuándo se activan las transacciones distribuidas

Es posible que no se dé cuenta de que su aplicación usa transacciones distribuidas. Se escalan automáticamente en estos escenarios:

// This creates a distributed transaction if conn1 and conn2 point to different servers
using (TransactionScope scope = new TransactionScope())
{
    using (SqlConnection conn1 = new SqlConnection("Server=Server1;Database=DB1;..."))
    using (SqlConnection conn2 = new SqlConnection("Server=Server2;Database=DB2;..."))
    {
        conn1.Open();
        // Execute work on Server1

        conn2.Open();  // This escalates to a distributed transaction
        // Execute work on Server2
    }
    scope.Complete();
}

Incluso abrir dos conexiones al mismo servidor puede escalar a MSDTC en algunos casos (antes de .NET 4.0 con SQL Server 2008).

Solución paso a paso

Paso 1: Configurar los ajustes de seguridad de MSDTC

Esto debe hacerse en ambas máquinas involucradas en la transacción.

  1. Abra Servicios de componentes ejecutando dcomcnfg
  2. Navegue a: Servicios de componentes > Equipos > Mi PC > Coordinador de transacciones distribuidas > DTC local
  3. Haga clic derecho en DTC local y seleccione Propiedades
  4. Vaya a la pestaña Seguridad
  5. Configure los siguientes ajustes:
AjusteValor
Acceso DTC de redMarcado
Permitir clientes remotosMarcado
Permitir entrantesMarcado
Permitir salientesMarcado
Autenticación mutua requeridaVer nota abajo
No se requiere autenticaciónSeleccione esto si las máquinas NO están en el mismo dominio
Habilitar transacciones XAMarcado (si usa XA)
Habilitar transacciones SNA LU 6.2Dejar desmarcado a menos que sea necesario

Nota sobre autenticación: Si ambas máquinas están en el mismo dominio de Active Directory, use Autenticación mutua requerida. Si están en dominios o grupos de trabajo diferentes, use No se requiere autenticación.

  1. Haga clic en Aceptar y confirme que desea reiniciar el servicio MSDTC

Paso 2: Configurar el Firewall de Windows

La excepción interna menciona específicamente el firewall. En Windows 7, Windows Server 2008 y versiones posteriores, debe habilitar explícitamente la excepción de firewall para MSDTC, incluso si cree que ya lo ha hecho.

Usando el Firewall de Windows con seguridad avanzada

# Enable the predefined MSDTC firewall rules (do this on BOTH machines)
Enable-NetFirewallRule -DisplayGroup "Distributed Transaction Coordinator"

O manualmente a través de la interfaz gráfica:

  1. Abra Firewall de Windows con seguridad avanzada (wf.msc)
  2. Haga clic en Reglas de entrada
  3. Busque las reglas en el grupo Coordinador de transacciones distribuidas
  4. Habilite todas (clic derecho > Habilitar regla):
    • Coordinador de transacciones distribuidas (RPC)
    • Coordinador de transacciones distribuidas (RPC-EPMAP)
    • Coordinador de transacciones distribuidas (TCP-In)

Repita para las reglas de salida también.

Configurar un puerto MSDTC fijo (recomendado para firewalls)

Por defecto, MSDTC usa puertos RPC dinámicos, lo que dificulta la configuración del firewall. Puede asignar un puerto fijo:

  1. Abra Servicios de componentes (dcomcnfg)
  2. Navegue a Mi PC > Coordinador de transacciones distribuidas > DTC local > Propiedades
  3. No hay interfaz gráfica para la configuración del puerto; use el registro:
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSDTC]
"ServerTcpPort"=dword:00001388

Esto configura MSDTC para usar el puerto TCP 5000 (0x1388). Luego cree una regla de firewall específica:

New-NetFirewallRule -DisplayName "MSDTC Fixed Port" -Direction Inbound -Protocol TCP -LocalPort 5000 -Action Allow
New-NetFirewallRule -DisplayName "MSDTC RPC" -Direction Inbound -Protocol TCP -LocalPort 135 -Action Allow

Después de cambiar el puerto, reinicie el servicio MSDTC:

Restart-Service -Name MSDTC

Paso 3: Verificar la resolución de nombres NetBIOS

Las dos máquinas deben poder resolver la otra por nombre NetBIOS, no solo por dirección IP o FQDN. MSDTC usa el nombre NetBIOS internamente.

Pruebe desde cada máquina:

:: From the client, test resolution of the server
ping SERVER1
nbtstat -a SERVER1

:: From the server, test resolution of the client
ping CLIENT1
nbtstat -a CLIENT1

Si la resolución de nombres falla, agregue entradas al archivo hosts en ambas máquinas:

# C:\Windows\System32\drivers\etc\hosts
10.0.1.10    SERVER1
10.0.1.20    CLIENT1

O mejor, asegúrese de que WINS o DNS con los registros apropiados esté configurado.

Paso 4: Verificar que el servicio MSDTC esté en ejecución

# Check MSDTC service status on both machines
Get-Service -Name MSDTC | Select-Object Name, Status, StartType

# Ensure it is set to start automatically
Set-Service -Name MSDTC -StartupType Automatic
Start-Service -Name MSDTC

Paso 5: Probar la comunicación de MSDTC

Use la herramienta DTCPing de Microsoft para probar la conectividad de MSDTC entre dos máquinas.

  1. Descargue DTCPing de Microsoft
  2. Ejecute dtcping.exe en ambas máquinas simultáneamente
  3. En cada máquina, ingrese el nombre NetBIOS de la otra máquina
  4. Haga clic en Ping: una prueba exitosa muestra “successfully completed” tanto para las pruebas RPC como de transacción

Alternativamente, pruebe desde PowerShell:

# Test RPC endpoint mapper connectivity
Test-NetConnection -ComputerName SERVER1 -Port 135

# Test the MSDTC fixed port (if configured)
Test-NetConnection -ComputerName SERVER1 -Port 5000

Transacciones distribuidas con SQL Server

Escenario: Consultas con servidor vinculado

Cuando SQL Server ejecuta una consulta a través de un servidor vinculado, MSDTC está involucrado:

-- This triggers a distributed transaction
BEGIN DISTRIBUTED TRANSACTION
    INSERT INTO LocalDB.dbo.Orders (OrderID, CustomerName)
    SELECT OrderID, CustomerName FROM [RemoteServer].RemoteDB.dbo.Orders
    WHERE OrderDate > '2024-01-01';
COMMIT TRANSACTION

Asegúrese de que MSDTC esté configurado en ambas máquinas de SQL Server.

Escenario: .NET TransactionScope

using (var scope = new TransactionScope())
{
    using (var conn = new SqlConnection(connectionString1))
    {
        conn.Open();
        using (var cmd = conn.CreateCommand())
        {
            cmd.CommandText = "INSERT INTO Table1 (Col1) VALUES ('Value1')";
            cmd.ExecuteNonQuery();
        }
    }

    using (var conn = new SqlConnection(connectionString2))
    {
        conn.Open();  // Escalates to distributed transaction
        using (var cmd = conn.CreateCommand())
        {
            cmd.CommandText = "INSERT INTO Table2 (Col1) VALUES ('Value2')";
            cmd.ExecuteNonQuery();
        }
    }

    scope.Complete();
}

Evitar transacciones distribuidas innecesarias

Si ambas conexiones apuntan a la misma instancia de SQL Server, puede evitar la escalación a MSDTC reutilizando una sola conexión:

using (var scope = new TransactionScope())
using (var conn = new SqlConnection(connectionString))
{
    conn.Open();

    using (var cmd1 = conn.CreateCommand())
    {
        cmd1.CommandText = "INSERT INTO DB1.dbo.Table1 (Col1) VALUES ('Value1')";
        cmd1.ExecuteNonQuery();
    }

    using (var cmd2 = conn.CreateCommand())
    {
        cmd2.CommandText = "INSERT INTO DB2.dbo.Table2 (Col1) VALUES ('Value2')";
        cmd2.ExecuteNonQuery();
    }

    scope.Complete();
}

Lista de verificación para solución de problemas

Recorra esta lista de verificación en ambas máquinas:

  1. El servicio MSDTC está en ejecución y configurado para inicio automático
  2. Los ajustes de seguridad de Servicios de componentes son correctos (Acceso DTC de red habilitado, Permitir entrantes/salientes)
  3. El Firewall de Windows tiene la excepción del Coordinador de transacciones distribuidas habilitada tanto para entrada como para salida
  4. La resolución de nombres NetBIOS funciona en ambas direcciones
  5. El mismo nivel de autenticación MSDTC en ambas máquinas (Autenticación mutua, Autenticación de llamador entrante, o Sin autenticación)
  6. El puerto RPC 135 es accesible entre las máquinas
  7. La prueba DTCPing tiene éxito en ambas direcciones
  8. El antivirus no está bloqueando el tráfico de MSDTC o RPC
  9. SQL Server tiene el acceso remoto habilitado (sp_configure 'remote access', 1)
  10. Entornos en clúster: Si SQL Server está en clúster, configure MSDTC como un recurso en clúster, no solo en los nodos individuales

Errores comunes

El Firewall de Windows “parece” abierto pero no lo está

En Windows 7 y Server 2008+, el firewall puede parecer que tiene las excepciones de MSDTC habilitadas, pero las reglas pueden estar aplicadas al perfil de red incorrecto (Dominio vs Privado vs Público). Verifique:

Get-NetFirewallRule -DisplayGroup "Distributed Transaction Coordinator" |
    Select-Object Name, Enabled, Profile, Direction

Asegúrese de que las reglas estén habilitadas para el perfil correcto.

Diferentes instancias de MSDTC en un clúster

En un clúster de conmutación por error de Windows Server, cada instancia en clúster de SQL Server debe tener su propio recurso MSDTC. El MSDTC local en el nodo puede no ser el que está manejando las transacciones para la instancia de SQL en clúster.

Corrupción del archivo de registro de MSDTC

Si el archivo de registro de MSDTC está corrupto, el servicio puede iniciarse pero fallar al procesar transacciones:

:: Reset the MSDTC log
msdtc -resetlog

Resumen

El error “Communication with the underlying transaction manager has failed” es un problema de configuración de firewall y MSDTC. Para solucionarlo, abra Servicios de componentes en ambas máquinas y habilite el Acceso DTC de red con Permitir entrantes y Permitir salientes. Luego habilite la excepción del Coordinador de transacciones distribuidas en el Firewall de Windows en ambas máquinas. Verifique que las máquinas puedan resolver la otra por nombre NetBIOS, y use DTCPing para validar la comunicación MSDTC de extremo a extremo.