Reputation: 43
It was possible in previous (<=0.84.0) versions of Rebus to Send message in TransactionScope and it was sent only if scope is completed
using (var scope = new TransactionScope())
{
var ctx = new AmbientTransactionContext();
sender.Send(recipient.InputQueue, msg, ctx);
scope.Complete();
}
Is it possible to achive the same behaviour in Rebus2
Upvotes: 3
Views: 980
Reputation: 18628
As you have correctly discovered, Rebus version >= 0.90.0 does not automatically enlist in ambient transactions.
(UPDATE: as of 0.99.16, the desired behavior can be had - see the end of this answer for details on how)
However this does not mean that Rebus cannot enlist in a transaction - it just uses its own ambient transaction mechanism (which does not depend on System.Transactions
and will be available when Rebus is ported to .NET core).
You can use Rebus' DefaultTransactionContext
and "make it ambient" with this AmbientRebusTransactionContext
:
/// <summary>
/// Rebus ambient transaction scope helper
/// </summary>
public class AmbientRebusTransactionContext : IDisposable
{
readonly DefaultTransactionContext _transactionContext = new DefaultTransactionContext();
public AmbientRebusTransactionContext()
{
if (AmbientTransactionContext.Current != null)
{
throw new InvalidOperationException("Cannot start a Rebus transaction because one was already active!");
}
AmbientTransactionContext.Current = _transactionContext;
}
public Task Complete()
{
return _transactionContext.Complete();
}
public void Dispose()
{
AmbientTransactionContext.Current = null;
}
}
which you can then use like this:
using(var tx = new AmbientRebusTransactionContext())
{
await bus.Send(new Message());
await tx.Complete();
}
or, if you're using it in a web application, I suggest you wrap it in an OWIN middleware like this:
app.Use(async (context, next) =>
{
using (var transactionContext = new AmbientRebusTransactionContext())
{
await next();
await transactionContext.Complete();
}
});
UPDATE: Since Rebus 0.99.16, the following has been supported (via the Rebus.TransactionScope
package):
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
scope.EnlistRebus(); //< enlist Rebus in ambient .NET tx
await _bus.SendLocal("hallå i stuen!1");
scope.Complete();
}
Upvotes: 2