public async Task CannotUseOutboxTwice() { await using var connection = new SqlConnection(ConnectionString); await connection.OpenAsync(); await using var transaction = connection.BeginTransaction(); using var scope = new RebusTransactionScope(); scope.UseOutbox(connection, transaction); Assert.Throws <InvalidOperationException>(() => scope.UseOutbox(connection, transaction)); }
public static void UseRebusOutbox(this IApplicationBuilder app, string connectionString) { app.Use(async(context, next) => { // if you've set up DI resolution to fetch the current connection/transaction from a unit of work, you can do something like this: //var serviceProvider = context.RequestServices; //var connection = serviceProvider.GetRequiredService<SqlConnection>(); //var transaction = serviceProvider.GetRequiredService<SqlTransaction>(); // but in this case we'll work with a simulated unit of work here: await using var connection = new SqlConnection(connectionString); await connection.OpenAsync(); await using var transaction = connection.BeginTransaction(); using var scope = new RebusTransactionScope(); scope.UseOutbox(connection, transaction); // process the web request await next(); // insert outgoing messages await scope.CompleteAsync(); // commit! await transaction.CommitAsync(); }); }
public async Task CanUseOutboxOutsideOfRebusHandler_Publish(bool commitTransaction, bool expectMessageToBeReceived) { var settings = new FlakySenderTransportDecoratorSettings(); using var messageWasReceived = new ManualResetEvent(initialState: false); using var server = CreateConsumer("server", a => a.Handle <SomeMessage>(async _ => messageWasReceived.Set())); await server.Subscribe <SomeMessage>(); using var client = CreateOneWayClient(flakySenderTransportDecoratorSettings: settings); // set success rate pretty low, so we're sure that it's currently not possible to use the // real transport - this is a job for the outbox! settings.SuccessRate = 0; // pretending we're in a web app - we have these two bad boys at work: await using (var connection = new SqlConnection(ConnectionString)) { await connection.OpenAsync(); await using var transaction = connection.BeginTransaction(); // this is how we would use the outbox for outgoing messages using var scope = new RebusTransactionScope(); scope.UseOutbox(connection, transaction); await client.Publish(new SomeMessage()); await scope.CompleteAsync(); if (commitTransaction) { // this is what we were all waiting for! await transaction.CommitAsync(); } } // we would not have gotten this far without the outbox - now let's pretend that the transport has recovered settings.SuccessRate = 1; // wait for server to receive the event Assert.That(messageWasReceived.WaitOne(TimeSpan.FromSeconds(15)), Is.EqualTo(expectMessageToBeReceived), $"When commitTransaction={commitTransaction} we {(expectMessageToBeReceived ? "expected the message to be sent and thus received" : "did NOT expect the message to be sent and therefore also not received")}"); }