> For the complete documentation index, see [llms.txt](https://brightercommand.gitbook.io/paramore-brighter-documentation/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://brightercommand.gitbook.io/paramore-brighter-documentation/outbox-and-inbox/brighteroutboxsupport/dapperoutbox.md).

# Dapper Outbox

The Dapper Outbox allows integration between Dapper and Brighter's outbox support.

> **Reference** · Applies to **Brighter V10**

## Dapper Outbox Usage

The Dapper Outbox allows integration between Dapper and [Brighter's outbox support](/paramore-brighter-documentation/outbox-and-inbox/brighteroutboxsupport.md). The configuration is described in [Command Processor Configuration Reference](/paramore-brighter-documentation/brighter-configuration/brighterbasicconfiguration/commandprocessorconfigurationreference.md#outbox-support).

Dapper needs no Brighter package of its own at V10. You need the *Outbox* package for your RDBMS and the package that carries its connection and transaction providers:

* **Paramore.Brighter.Outbox.{DB}**
* **Paramore.Brighter.{DB}**

Obviously, {DB} should match. In the example below we use MySql, so we would need the following packages, alongside **Dapper** itself:

* **Paramore.Brighter.Outbox.MySql**
* **Paramore.Brighter.MySql**

> **Coming from V9?** The **Paramore.Brighter.{DB}.Dapper** packages stopped at 9.9.13 and there is no V10 release of any of them. Their Unit of Work is now **IAmATransactionConnectionProvider**, which lives in the **Paramore.Brighter.{DB}** package and hands you the same **DbConnection** and **DbTransaction** Dapper's extension methods take.

As described in [Command Processor Configuration Reference](/paramore-brighter-documentation/brighter-configuration/brighterbasicconfiguration/commandprocessorconfigurationreference.md#outbox-support), we configure Brighter to use an outbox by setting **Outbox** on the options passed to **AddProducers()**.

As we want to use Dapper, we also set **ConnectionProvider** and **TransactionProvider** so that we can share your transaction scope when persisting messages to the outbox.

```csharp
using Microsoft.Extensions.DependencyInjection;
using Paramore.Brighter;
using Paramore.Brighter.Extensions.DependencyInjection;
using Paramore.Brighter.Inbox.MySql;
using Paramore.Brighter.MySql;
using Paramore.Brighter.Outbox.Hosting;
using Paramore.Brighter.Outbox.MySql;
using Paramore.Brighter.ServiceActivator.Extensions.DependencyInjection;

public void ConfigureServices(IServiceCollection services)
{
    var configuration = new RelationalDatabaseConfiguration(
        connectionString,
        databaseName: "brighter_test",
        outBoxTableName: "outbox_messages",
        inboxTableName: "inbox_messages");

    services.AddSingleton<IAmARelationalDatabaseConfiguration>(configuration);

    services.AddConsumers(options =>
        {
            options.InboxConfiguration = new InboxConfiguration(new MySqlInbox(configuration));
        })
        .AddProducers(configure =>
        {
            configure.Outbox = new MySqlOutbox(configuration);
            configure.ConnectionProvider = typeof(MySqlConnectionProvider);
            configure.TransactionProvider = typeof(MySqlTransactionProvider);
        })
        .UseOutboxSweeper()
        .AutoFromAssemblies();
}

```

The handler below is `AddGreetingHandlerAsync` from the Brighter sample at `Brighter/samples/WebAPI/WebAPI_Dapper/`, which also declares the `AddGreeting` request, the `Person` and `Greeting` entities and the `GreetingMade` event it uses.

In our handler we take a dependency on Brighter's **IAmATransactionConnectionProvider**. We explicitly start a transaction within the handler on the Database within the provider. Dapper provides extension methods on a DbConnection for typical CRUD operations. Our provider wraps that DbConnection, and allows you to create a DB transaction associated with that DbConnection. You must use our method, and not create the transaction directly via the connection, because we cannot obtain that transaction. Sharing that transaction allows us to insert a message into the Outbox within the same transaction.

We call **DepositPostAsync** within that transaction to write the message to the Outbox. Once the transaction has closed we can call **ClearOutboxAsync** to immediately clear, or we can rely on the Outbox Sweeper, if we have configured one to clear for us. (There are equivalent synchronous versions of these APIs).

```csharp
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Dapper;
using Microsoft.Extensions.Logging;
using Paramore.Brighter;

public class AddGreetingHandlerAsync : RequestHandlerAsync<AddGreeting>
{
    private readonly IAmATransactionConnectionProvider _transactionProvider;
    private readonly IAmACommandProcessor _postBox;
    private readonly ILogger<AddGreetingHandlerAsync> _logger;

    public AddGreetingHandlerAsync(IAmATransactionConnectionProvider transactionProvider,
        IAmACommandProcessor postBox,
        ILogger<AddGreetingHandlerAsync> logger)
    {
        _transactionProvider = transactionProvider;
        _postBox = postBox;
        _logger = logger;
    }

    public override async Task<AddGreeting> HandleAsync(AddGreeting addGreeting, CancellationToken cancellationToken = default)
    {
        var posts = new List<Id>();

        //We use the transaction provider to grab connection and transaction, because Outbox needs
        //to share them 'behind the scenes'
        DbConnection conn = await _transactionProvider.GetConnectionAsync(cancellationToken);
        DbTransaction tx = await _transactionProvider.GetTransactionAsync(cancellationToken);
        try
        {
            var people = await conn.QueryAsync<Person>(
                "select * from Person where name = @name",
                new { name = addGreeting.Name },
                tx);
            var person = people.Single();

            var greeting = new Greeting(addGreeting.Greeting, person);

            //write the added child entity to the Db
            await conn.ExecuteAsync(
                "insert into Greeting (Message, Recipient_Id) values (@Message, @RecipientId)",
                new { greeting.Message, greeting.RecipientId },
                tx);

            //Now write the message we want to send to the Db in the same transaction.
            posts.Add(await _postBox.DepositPostAsync(
                new GreetingMade(greeting.Greet()),
                _transactionProvider,
                cancellationToken: cancellationToken));

            //commit both new greeting and outgoing message
            await _transactionProvider.CommitAsync(cancellationToken);
        }
        catch (Exception e)
        {
            _logger.LogError(e, "Exception thrown handling Add Greeting request");
            //it went wrong, rollback the entity change and the downstream message
            await _transactionProvider.RollbackAsync(cancellationToken);
            return await base.HandleAsync(addGreeting, cancellationToken);
        }
        finally
        {
            _transactionProvider.Close();
        }

        //Send this message via a transport. We need the ids to send just the messages here, not all outstanding ones.
        //Alternatively, you can let the Sweeper do this, but at the cost of increased latency
        await _postBox.ClearOutboxAsync(posts, cancellationToken: cancellationToken);

        return await base.HandleAsync(addGreeting, cancellationToken);
    }
}
```

## Brighter Unit of Work without Dapper

Because Brighter's transaction provider just wraps a DbConnection and its associated transaction, it can be used to provide a DbTransaction that works with the outbox whenever you want to use DbConnection to interface with a database. Whilst Dapper adds value on top of DbConnection, it is just a set of extension methods, and our transaction provider does not depend upon Dapper itself.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://brightercommand.gitbook.io/paramore-brighter-documentation/outbox-and-inbox/brighteroutboxsupport/dapperoutbox.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `build a script that syncs our docs to a CMS` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
