-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
Description
When disposing of a TransactionScope object in .NET 7 code - where the transaction has been promoted to a distributed transaction and work has taken place in another process - the code blocks indefinitely.
Reproduction Steps
I encountered this when converting one of our .NET 4.8 ASP.NET web api applications to .NET 7, but I have written a simple console app that demonstrates this blocking behaviour - https://github.com/nathangreaves/NET7RC1-MSDTC-TestApp.
It contains 2 projects that have virtually the same code. One is targeting .NET 7 RC1, the other is .NET Framework 4.8.
The code starts a new TransactionScope, inserts a value into a database table, and writes the transmitter propagation token to a file on disk. When running the application a second time as a new instance, it will read this file, create a new TransactionScope (using the Transaction from the transmitter propogation token), and insert a value into a database table. It deletes the file following completion of the transaction. The first instance will then complete the outer transaction, and then repeat the whole process a second time.
The code in .NET Framework 4.8 works correctly, committing both transactions and continuing execution.
However the .NET 7 code blocks on disposing the outer transaction. Also the Inner Transaction throws the following exception which may be relevant:
System.Threading.SynchronizationLockException: Object synchronization method was called from an unsynchronized block of code.
at System.Threading.Monitor.Exit(Object obj)
at System.Transactions.DependentTransaction.Complete()
at System.Transactions.TransactionScope.InternalDispose()
at System.Transactions.TransactionScope.Dispose()
However, if you run the applications in the following order:
- Outer transaction using .NET 7 project
- Inner transaction using .NET Framework 4.8 project
The inner transaction completes successfully with the above exception, and the outer transaction (.NET 7) still blocks.
I attached the debugger to the .NET 7 project whilst it was blocked:

This screenshot shows the code has blocked waiting for a lock in transactionScope.Dispose();
The following screenshots show the output of the console applications for all of the scenarios in terms of which version of .NET is running for the 2 instances of the console application:
Outer Transaction .NET 7, Inner Transaction .NET 7 - outer transaction blocks on dispose, inner transaction throws SynchronizationLockException exception:

Outer Transaction .NET 7, Inner Transaction .NET 4.8 - outer transaction blocks on dispose, inner transaction successful:

Outer Transaction .NET 4.8, Inner Transaction .NET 7 - outer transactions complete, inner transactions throw SynchronizationLockException on dispose (but still complete):

Outer Transaction .NET 4.8, Inner Transaction .NET 4.8 - outer and inner transactions complete and execution continues

Expected behavior
Execution does not block on transactionScope.Dispose() when completing a distributed transaction.
Execution does not throw exception System.Threading.SynchronizationLockException when completing a distributed transaction.
Actual behavior
When disposing of a TransactionScope object in .NET 7 code - where the transaction has been promoted to a distributed transaction and work has taken place in another process - the code blocks indefinitely.
Regression?
This code works correctly in .NET Framework 4.8
Known Workarounds
No response
Configuration
.NET 7 RC1
Windows Server 2019 Standard - 1809 (17763.2565)
x64
Other information
No response