MSDTC - Communication with the underlying transaction manager has failed (Firewall open, MSDTC network access on)

StackOverflow https://stackoverflow.com/questions/2498372

  •  21-09-2019
  •  | 
  •  

Question

I'm having problems with my ASP.NET web forms system.

It worked on our test server but now we are putting it live one of the servers is within a DMZ and the SQL server is outside of that (on our network still though - although a different subnet)

I have open up the firewall completely between these two boxes to see if that was the issue and it still gives the error message "Communication with the underlying transaction manager has failed" whenever we try and use the "TransactionScope". We can access the data for retrieval it's just transactions that break it.

We have also used msdtc ping to test the connection and with the amendments on the firewall that pings successfully, but the same error occurs!

How do i resolve this error?

Any help would be great as we have a system to go live today. Panic :)

Edit: I have created a more straightforward test page with a transaction as below and this works fine. Could a nested transaction cause this kind of error and if so why would this only cause an issue when using a live box in a dmz with a firewall?

AuditRepository auditRepository = new AuditRepository();

            try
            {
                using (TransactionScope scope = new TransactionScope())
                {
                    auditRepository.Add(DateTime.Now, 1, "TEST-TRANSACTIONS#1", 1);
                    auditRepository.Save();
                    auditRepository.Add(DateTime.Now, 1, "TEST-TRANSACTIONS#2", 1);
                    auditRepository.Save();

                    scope.Complete();
                }
            }
            catch (Exception ex)
            {
                Response.Write("Test Error For Transaction: " + ex.Message + "<br />" + ex.StackTrace);
            }

This is the ErrorStack we are getting when the problem occurs: at

System.Transactions.TransactionInterop.GetOletxTransactionFromTransmitterPropigationToken(Byte[]
  propagationToken) at
  System.Transactions.TransactionStatePSPEOperation.PSPEPromote(InternalTransaction tx)
  at System.Transactions.TransactionStateDelegatedBase.EnterState(InternalTransaction tx)
  at System.Transactions.EnlistableStates.Promote(InternalTransaction tx) at
  System.Transactions.Transaction.Promote() at
  System.Transactions.TransactionInterop.ConvertToOletxTransaction(Transaction
  transaction) at System.Transactions.TransactionInterop.GetExportCookie(Transaction
  transaction, Byte[] whereabouts) at
  System.Data.SqlClient.SqlInternalConnection.GetTransactionCookie(Transaction
  transaction, Byte[] whereAbouts) at
  System.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx) at
  System.Data.SqlClient.SqlInternalConnection.Enlist(Transaction tx) at
  System.Data.SqlClient.SqlInternalConnectionTds.Activate(Transaction transaction) at
  System.Data.ProviderBase.DbConnectionInternal.ActivateConnection(Transaction
  transaction) at System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection
  owningObject) at
  System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection
  owningConnection) at
  System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection
  outerConnection, DbConnectionFactory connectionFactory) at
  System.Data.SqlClient.SqlConnection.Open() at
  System.Data.Linq.SqlClient.SqlConnectionManager.UseConnection(IConnectionUser user) at
  System.Data.Linq.SqlClient.SqlProvider.get_IsSqlCe() at
  System.Data.Linq.SqlClient.SqlProvider.InitializeProviderMode() at
  System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression
  query) at
  System.Data.Linq.ChangeDirector.StandardChangeDirector.DynamicInsert(TrackedObject
  item) at System.Data.Linq.ChangeDirector.StandardChangeDirector.Insert(TrackedObject
  item) at System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode) at
  System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode) at
  System.Data.Linq.DataContext.SubmitChanges() at RegBook.classes.DbBase.Save() at
  RegBook.usercontrols.BookingProcess.confirmBookingButton_Click(Object sender, EventArgs e)
Was it helpful?

Solution

I realised the code I provided would not escalate the transaction to the DTC. I was getting the problem when using multiple data contexts within one transaction.

Although I thought the firewall was open it needed a range of ports and that was why the problem was still occuring.

This article helped me resolve it

OTHER TIPS

In my case, I was trying it over VPN. It was working perfectly fine in LAN but not in VPN. I also opened the ports (i.e. 135,5000-5020) in Hardware Firewall at both sites but invain. After searching a lot over it, I came to know that BOTH THE MACHINES SHOULD BE ABLE TO COMMUNICATE WITH THEIR NetBIOS NAME. I just added the entry of another machin in the hosts file & it is now wroking perfectly fine.

Thanks Andrew & Mike for the valuable help.

Thank you.

I understand you can open ports and configure MSDTC, but not for all the clients where your app is installed. Is there a way to block TransactionScope from promoting to DTC. I know I am working with one DB only. I just need multiple contexts in order to dispose context with changes made in error or after error occured. THe best way of course is to detach object from a data context, but this feature is not available in .NET 3.5SP1 Linq to SQL. So I have to submit changes under a different context and throw it away if something goes wrong.

Here is some powershell script that can make all the changes required to get DTC to work properly. You have to run this on both machines that are participating in the transaction, i.e. your web server and the sql server machine.

function Enable-MSDTC
{
    [CmdletBinding()]
    param()

    Write-Host "Updating registry entries for MSDTC"
    $msdtcRegKey = "HKLM:\SOFTWARE\Microsoft\MSDTC\Security" 

    Set-ItemProperty  -Path $msdtcRegKey -Name "NetworkDtcAccessTransactions" -Value 1
    Set-ItemProperty -Path $msdtcRegKey -Name "NetworkDtcAccess" -Value 1
    Set-ItemProperty -Path $msdtcRegKey -Name "NetworkDtcAccessOutbound" -Value 1
    Set-ItemProperty -Path $msdtcRegKey -Name "NetworkDtcAccessClients" -Value 1
    Set-ItemProperty -Path $msdtcRegKey -Name "NetworkDtcAccessInbound" -Value 1
    Set-ItemProperty -Path $msdtcRegKey -Name "LuTransactions" -Value 1

   #Configure MSDTC to use specific ports
   #see: https://support.microsoft.com/en-us/kb/250367
   $msdtcPortKey = "HKLM:\SOFTWARE\Microsoft\Rpc\Internet"
   New-Item -Path $msdtcPortKey
   New-ItemProperty -Path $msdtcPortKey -Name "Ports" -PropertyType "MultiString" -Value "5000-5200"
   New-ItemProperty -Path $msdtcPortKey -Name "PortsInternetAvailable" -PropertyType "String" -Value "Y"
   New-ItemProperty -Path $msdtcPortKey -Name "UseInternetPorts" -PropertyType "String" -Value "Y"

   #open firewall ports 135, 1433, 5000-5100
   #also add MSDTC program exclusion

    netsh advfirewall firewall add rule name='MSDTC Endpoint Mapper (In)' localport=135 dir=in action=allow protocol=TCP
    netsh advfirewall firewall add rule name='MSDTC SQL Server (In)' localport=1433 dir=in action=allow protocol=TCP
    netsh advfirewall firewall add rule name='MSDTC Dynamic Ports (In)' localport=5000-5200 dir=in action=allow protocol=TCP
    netsh advfirewall firewall add rule name='MSDTC exe' dir=in action=allow program=$env:windir\system32\msdtc.exe enable=yes

    Write-Host "Restarting MSDTC service"
    #restart the MSDTC service
    Restart-Service MSDTC -Force -Confirm:$false
}

Enable-MSDTC -ErrorAction SilentlyContinue
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top