When your .NET application needs to perform operations across multiple resources (for example, two SQL Server databases, MSMQ, or another transactional resource) and you want them all to succeed or fail together, you can use MSDTC (Microsoft Distributed Transaction Coordinator).

Key idea: MSDTC ensures atomicity across multiple systems. If one operation fails, the transaction coordinator rolls back all other operations automatically.

💡 What is MSDTC?

The Microsoft Distributed Transaction Coordinator (MSDTC) is a Windows service that coordinates transactions that span multiple resource managers, such as:

🔗 How It Works

When you use TransactionScope in .NET and your code accesses more than one transactional resource, the .NET Framework automatically promotes the transaction to a distributed transaction.

The transaction coordinator (MSDTC) then ensures that:

⚙️ Prerequisites

// To check MSDTC service
services.msc
// or from cmd
net start msdtc

🧩 Example 1: Distributed Transaction with Two SQL Databases

using System;
using System.Data.SqlClient;
using System.Transactions;

class Program
{
    static void Main()
    {
        string connStr1 = "Data Source=SQLSERVER1;Initial Catalog=DbA;Integrated Security=True;";
        string connStr2 = "Data Source=SQLSERVER2;Initial Catalog=DbB;Integrated Security=True;";

        using (var scope = new TransactionScope())
        {
            using (var conn1 = new SqlConnection(connStr1))
            using (var conn2 = new SqlConnection(connStr2))
            {
                conn1.Open();
                conn2.Open();

                var cmd1 = new SqlCommand("INSERT INTO Orders (OrderId, Amount) VALUES (1, 500)", conn1);
                var cmd2 = new SqlCommand("INSERT INTO AuditLog (LogId, Description) VALUES (1, 'Order created')", conn2);

                cmd1.ExecuteNonQuery();
                cmd2.ExecuteNonQuery();
            }

            // If we reach here, both commands succeeded
            scope.Complete();
        }

        Console.WriteLine("✅ Both databases committed successfully!");
    }
}

What happens

  1. When you open two SQL connections within the same TransactionScope, .NET automatically promotes the transaction to MSDTC.

  2. MSDTC coordinates the commit between both databases.

  3. If either cmd1 or cmd2 fails, the whole transaction rolls back.

Important: If you open only one connection, the transaction remains local and MSDTC is not used.

🧠 Example 2: Distributed Transaction in Entity Framework

using (var scope = new TransactionScope())
{
    using (var db1 = new SalesDbContext())
    {
        db1.Orders.Add(new Order { OrderId = 100, Amount = 1200 });
        db1.SaveChanges();
    }

    using (var db2 = new AuditDbContext())
    {
        db2.AuditLogs.Add(new AuditLog { LogId = 100, Description = "Order 100 created" });
        db2.SaveChanges();
    }

    // Commit only if both succeed
    scope.Complete();
}

Entity Framework internally uses ADO.NET connections, so MSDTC is automatically involved when multiple connections are opened within a TransactionScope.

🛠️ Troubleshooting MSDTC

IssueSolution
“MSDTC not available”Start the service: net start msdtc
“Transaction manager has disabled its support for remote/network transactions”Enable Network DTC Access in dcomcnfg → Component Services → Computers → My Computer → Distributed Transaction Coordinator → Properties → Security
TimeoutSet custom timeout via TransactionOptions.Timeout.
Firewall issuesAllow DTC TCP port (default: 135) and dynamic ports.

⚖️ TransactionScope Options

var options = new TransactionOptions
{
    IsolationLevel = IsolationLevel.ReadCommitted,
    Timeout = TimeSpan.FromMinutes(2)
};

using (var scope = new TransactionScope(
    TransactionScopeOption.Required, options))
{
    // Your code here
}

🚫 When Not to Use MSDTC

MSDTC is powerful but not suitable for all scenarios:

✅ Best Practices

Summary

MSDTC provides guaranteed atomicity for operations involving multiple transactional resources. In modern .NET systems, use it when working across multiple SQL databases or legacy systems on Windows environments. For cloud or microservices, prefer patterns like the Saga or Outbox pattern.