> 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/efcoreoutbox.md).

# EF Core Outbox

The EFCore Outbox allows integration between EF Core and Brighter's outbox support.

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

## EF Core Outbox Usage

The EFCore Outbox allows integration between EF Core 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).

For this we will need the *Outbox* package for EF Core. Packages for EF Core exist for the following RDBMS: MSSQL, MYSQL, Postgres, and Sqlite. Packages have the naming convention:

* **Paramore.Brighter.{DB}.EntityFrameworkCore**

In addition, you will need the Outbox package for the relevant RDBMS:

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

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

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

**Paramore.Brighter.MySql.EntityFrameworkCore** will pull in another package

* **Paramore.Brighter.MySql**

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

As we want to use EF Core, we also set its `TransactionProvider` to the EF Core transaction provider for your `DbContext`, so that we can share your transaction when persisting messages to the outbox. Brighter creates both providers from your container, so register what they are built from: the database configuration and the `DbContext`.

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

public void ConfigureServices(IServiceCollection services)
{
    var outboxConfiguration = new RelationalDatabaseConfiguration(DbConnectionString());
    services.AddSingleton<IAmARelationalDatabaseConfiguration>(outboxConfiguration);
    services.AddDbContext<GreetingsEntityGateway>(options =>
        options.UseMySql(DbConnectionString(), ServerVersion.AutoDetect(DbConnectionString())));

    services.AddBrighter()
        .AddProducers(producers =>
        {
            // ... your producer registry
            producers.Outbox = new MySqlOutbox(outboxConfiguration);
            producers.ConnectionProvider = typeof(MySqlConnectionProvider);
            // Use the EF Core transaction provider with your DbContext
            producers.TransactionProvider = typeof(MySqlEntityFrameworkTransactionProvider<GreetingsEntityGateway>);
        })
        .UseOutboxSweeper();
}
```

In our handler we take a dependency on our EF Core context (derived from `DbContext`) and on the `IAmATransactionConnectionProvider` that Brighter registers for the `TransactionProvider` set above. We start the transaction through the provider, which begins it on the context's database, so EF Core's `SaveChangesAsync` and the Outbox write share it.

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

```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Paramore.Brighter;

public class AddGreetingHandlerAsync(
    GreetingsEntityGateway uow,
    IAmATransactionConnectionProvider provider,
    IAmACommandProcessor postBox)
    : RequestHandlerAsync<AddGreeting>
{
    public override async Task<AddGreeting> HandleAsync(AddGreeting addGreeting, CancellationToken cancellationToken = default)
    {
        var posts = new List<Id>();

        await provider.GetTransactionAsync(cancellationToken);
        try
        {
            var person = await uow.People
                .Where(p => p.Name == addGreeting.Name)
                .SingleAsync(cancellationToken);

            var greeting = new Greeting(addGreeting.Greeting);

            person.AddGreeting(greeting);

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

            //write the changed entity to the Db
            await uow.SaveChangesAsync(cancellationToken);

            //write new person and the associated message to the Db
            await provider.CommitAsync(cancellationToken);
        }
        catch (Exception)
        {
            //it went wrong, rollback the entity change and the downstream message
            await provider.RollbackAsync(cancellationToken);
            return await base.HandleAsync(addGreeting, cancellationToken);
        }
        finally
        {
            provider.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);
    }
}
```


---

# 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 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/efcoreoutbox.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 `automate deployments from our CI pipeline` 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.
