Transaction configuration changes in Version 6

Component: NServiceBus

Version 6 provide a configuration API that is more aligned with the transaction capabilities of the transport.

Enabling transactions

Transactions are enabled by default so calls to .Enable() can safely be removed.

6.x NServiceBus
// Using a transport will enable transactions automatically.
endpointConfiguration.UseTransport<MyTransport>();
5.x NServiceBus
var transactionSettings = busConfiguration.Transactions();
transactionSettings.Enable();

Disabling transactions

Disabling transactions is now done by setting a transport transaction mode.

6.x NServiceBus
var transport = endpointConfiguration.UseTransport<MyTransport>();
transport.Transactions(TransportTransactionMode.None);
5.x NServiceBus
var transactionSettings = busConfiguration.Transactions();
transactionSettings.Disable();

Enabling distributed transactions

Distributed transactions is the default mode for transports with DTC support but can be enabled explicitly.

6.x NServiceBus
var transport = endpointConfiguration.UseTransport<MyTransport>();
transport.Transactions(TransportTransactionMode.TransactionScope);
5.x NServiceBus
var transactionSettings = busConfiguration.Transactions();
transactionSettings.EnableDistributedTransactions();

Disabling distributed transactions

Disabling distributed transactions is now done by setting a transport transaction mode.

6.x NServiceBus
var transport = endpointConfiguration.UseTransport<MyTransport>();
transport.Transactions(TransportTransactionMode.ReceiveOnly);
5.x NServiceBus
var transactionSettings = busConfiguration.Transactions();
transactionSettings.DisableDistributedTransactions();

Or, if the transport supports native AtomicWithReceive:

6.x NServiceBus
var transport = endpointConfiguration.UseTransport<MyTransport>();
transport.Transactions(TransportTransactionMode.SendsAtomicWithReceive);

Controlling transaction scope options

Version 6 allows transaction scope options to be configured at the transport level. Setting isolation level and timeout can now be done with the following:

6.x NServiceBus
var transport = endpointConfiguration.UseTransport<MyTransport>();
transport.Transactions(TransportTransactionMode.TransactionScope);
transport.TransactionScopeOptions(
    isolationLevel: IsolationLevel.RepeatableRead,
    timeout: TimeSpan.FromSeconds(30));
5.x NServiceBus
var transactionSettings = busConfiguration.Transactions();
transactionSettings.IsolationLevel(IsolationLevel.RepeatableRead);
transactionSettings.DefaultTimeout(TimeSpan.FromSeconds(30));

Wrapping handlers execution in a transaction scope

Version 6 comes with a unit of work that wraps execution of handlers in a transaction scope, which can now be done with this API:

6.x NServiceBus
var unitOfWork = endpointConfiguration.UnitOfWork();
unitOfWork.WrapHandlersInATransactionScope();
5.x NServiceBus
var transactionSettings = busConfiguration.Transactions();
transactionSettings.WrapHandlersExecutionInATransactionScope();

Forwarding messages to error queue when transactions are disabled

When transactions are disabled and if any errors are encountered during the processing of the message then the messages will be forwarded to the error queue. In Version 5, this message would have been lost. For more details, read the new behavior changes in Version 6.

Suppressing the ambient transaction

config.Transactions().DoNotWrapHandlersExecutionInATransactionScope() has been removed since transaction scopes are no longer used by non DTC transports to delay the dispatch of all outgoing operations until handlers have been executed.

In Version 6, handlers will only be wrapped in a TransactionScope if the given transport chooses to do so. Transports that do this in their default configuration include MSMQ and SQL Server. This means that performing storage operations against data sources that also support transaction scopes will escalate to a distributed transaction. Opting out of this behavior can be done with the following:

6.x NServiceBus
var transport = endpointConfiguration.UseTransport<MyTransport>();
transport.Transactions(TransportTransactionMode.ReceiveOnly);
5.x NServiceBus
var transactions = busConfiguration.Transactions();
transactions.DoNotWrapHandlersExecutionInATransactionScope();

For more information see Transport transaction - Sends atomic with Receive.

Version 6 leans on native transport transaction and the new batched dispatch support to achieve the same level of consistency with better performance.

Suppressing the ambient transaction created by the MSMQ and SQL Server transports can still be achieved by creating a custom pipeline behavior with a suppressed transaction scope.

Access to runtime settings

The following properties have been obsoleted on TransactionSettings class.

SuppressDistributedTransactions

To determine if distributed transactions are suppressed.

6.x NServiceBus
var transactionModeForReceives = readOnlySettings.GetRequiredTransactionModeForReceives();
var suppressDistributedTransactions = transactionModeForReceives != TransportTransactionMode.TransactionScope;
5.x NServiceBus
var suppressDistributedTransactions = transactionSettings.SuppressDistributedTransactions;

IsTransactional

To determine if transactions are enabled.

6.x NServiceBus
var transactionModeForReceives = readOnlySettings.GetRequiredTransactionModeForReceives();
var isTransactional = transactionModeForReceives != TransportTransactionMode.None;
5.x NServiceBus
var isTransactional = transactionSettings.IsTransactional;

Last modified