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));
    }
Beispiel #2
0
    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")}");
    }