What is MSDTC, when to use it and how to configure it
The Microsoft Distributed Transaction Coordinator (MSDTC) service is a component of modern versions of Microsoft Windows that is responsible for coordinating transactions that span multiple resource managers, such as databases, message queues, and file systems. MSDTC is included in Windows 2000 and later operating systems, and is also available for Windows NT 4.0.
When you want to provide the transaction to another object in another application domain (including across process and machine boundaries) on the same computer, the System.Transactions infrastructure automatically escalates the transaction to be managed by the Microsoft Distributed Transaction Coordinator (MSDTC). The escalation also occurs if you enlist another durable resource manager. When escalated, the transaction remains managed in its elevated state until its completion. How Escalation is Initiated. The most common scenario is when you open nested database connections in a single transaction.
If your APP(or web app) and MSSQL are running on the same machine, just need to make sure the MSDTC service (Distributed Transaction Coordinator) is not disabled, as it will be automatically started by the transaction escalation. Local DTC connections does not need to go through network, so the firewall exception and Network DTC Access would not affect much more.
If your APP(or web app) and MSSQL are running on different machines, you will need to configure following
On web server
Component Services > Distributed Transaction Coordinator > Local DTC > right-click > Properties > Security
The Microsoft Distributed Transaction Coordinator service must run under the NT AUTHORITY\NetworkService Windows account and have to enable it as the above, otherwise, you will get this error
add firewall exception on Inbound Rules for related webserver's IP, TCP with any ports, same as the previous.
Particular cases:
- does not add firewall exception
- could not find each other using hostname in the same Domain
- (if they are not in the same Domain, they will find each other by IP)
- MSDTC is not assigned a unique CID value
- to list:
-
PowerShell >Get-ChildItem Microsoft.PowerShell.Core\Registry::HKEY_CLASSES_ROOT\CID | Select-Object Name
-
- to list:
-
- to uninstall
-
PowerShell >msdtc -uninstall
-
- to install
-
PowerShell >msdtc -install
-
- require reboot system to apply changes, else, you will get error "MSDTC service on "Server_Name" is unavailable.
- to uninstall
corresponding error
Additional:
// This function takes arguments for 2 connection strings and commands to create a transaction
// involving two SQL Servers. It returns a value > 0 if the transaction is committed, 0 if the
// transaction is rolled back. To test this code, you can connect to two different databases
// on the same server by altering the connection string, or to another 3rd party RDBMS by
// altering the code in the connection2 code block.
static public int CreateTransactionScope(
string connectString1, string connectString2,
string commandText1, string commandText2)
{
// Initialize the return value to zero and create a StringWriter to display results.
int returnValue = 0;
System.IO.StringWriter writer = new System.IO.StringWriter();
try
{
// Create the TransactionScope to execute the commands, guaranteeing
// that both commands can commit or roll back as a single unit of work.
using (TransactionScope scope = new TransactionScope())
{
using (SqlConnection connection1 = new SqlConnection(connectString1))
{
// Opening the connection automatically enlists it in the
// TransactionScope as a lightweight transaction.
connection1.Open();
// Create the SqlCommand object and execute the first command.
SqlCommand command1 = new SqlCommand(commandText1, connection1);
returnValue = command1.ExecuteNonQuery();
writer.WriteLine("Rows to be affected by command1: {0}", returnValue);
// If you get here, this means that command1 succeeded. By nesting
// the using block for connection2 inside that of connection1, you
// conserve server and network resources as connection2 is opened
// only when there is a chance that the transaction can commit.
using (SqlConnection connection2 = new SqlConnection(connectString2))
{
// The transaction is escalated to a full distributed
// transaction when connection2 is opened.
connection2.Open();
// Execute the second command in the second database.
returnValue = 0;
SqlCommand command2 = new SqlCommand(commandText2, connection2);
returnValue = command2.ExecuteNonQuery();
writer.WriteLine("Rows to be affected by command2: {0}", returnValue);
}
}
// The Complete method commits the transaction. If an exception has been thrown,
// Complete is not called and the transaction is rolled back.
scope.Complete();
}
}
catch (TransactionAbortedException ex)
{
writer.WriteLine("TransactionAbortedException Message: {0}", ex.Message);
}
// Display messages.
Console.WriteLine(writer.ToString());
return returnValue;
}
Related links:
Troubleshooting Problems with MSDTC
Implementing an Implicit Transaction using Transaction Scope