Swevo.EFCore.Outbox 1.0.1

Prefix Reserved
dotnet add package Swevo.EFCore.Outbox --version 1.0.1
                    
NuGet\Install-Package Swevo.EFCore.Outbox -Version 1.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Swevo.EFCore.Outbox" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Swevo.EFCore.Outbox" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="Swevo.EFCore.Outbox" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Swevo.EFCore.Outbox --version 1.0.1
                    
#r "nuget: Swevo.EFCore.Outbox, 1.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Swevo.EFCore.Outbox@1.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Swevo.EFCore.Outbox&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=Swevo.EFCore.Outbox&version=1.0.1
                    
Install as a Cake Tool

Swevo.EFCore.Outbox

NuGet Build License: MIT

Transactional outbox pattern for EF Core + MassTransit. Enqueue domain events inside your existing SaveChanges transaction and publish them reliably via a background processor — zero message loss even if the bus is temporarily unavailable.


How It Works

┌─────────────────────────────────────────────────┐
│  Your service                                   │
│                                                 │
│  1. outbox.Add(new OrderPlaced(...))            │
│  2. dbContext.SaveChangesAsync()                │
│                                                 │
│  ┌──────────────────┐  atomic  ┌────────────┐  │
│  │  domain changes  │──────────│  OutboxMsg │  │
│  └──────────────────┘          └────────────┘  │
└─────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────┐
│  OutboxProcessor (BackgroundService)            │
│                                                 │
│  3. SELECT * FROM OutboxMessages WHERE          │
│        ProcessedAt IS NULL ORDER BY CreatedAt   │
│  4. publisher.Publish(message)                  │
│  5. UPDATE ProcessedAt = NOW()                  │
└─────────────────────────────────────────────────┘

Installation

dotnet add package Swevo.EFCore.Outbox

Requires EF Core 8+ and MassTransit 9+.


Quick Start

1. Configure your DbContext

public class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(options)
{
    public DbSet<OutboxMessage> OutboxMessages => Set<OutboxMessage>();

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.AddOutboxMessages(); // registers the OutboxMessage entity
    }
}

2. Register services

// Program.cs
builder.Services.AddOutbox<AppDbContext>(options =>
{
    options.PollingInterval = TimeSpan.FromSeconds(5); // default: 10s
    options.BatchSize = 50;                            // default: 100
});

builder.Services.AddDbContext<AppDbContext>((sp, options) =>
{
    options.UseSqlServer(connectionString);
    options.AddOutboxInterceptor(sp); // wires the scoped interceptor
});

3. Use in your services

public class OrderService(IOutbox outbox, AppDbContext db)
{
    public async Task PlaceOrder(PlaceOrderCommand cmd)
    {
        db.Orders.Add(new Order { Id = cmd.OrderId, Total = cmd.Total });

        // Enqueued atomically — written in the same SaveChanges transaction
        outbox.Add(new OrderPlaced(cmd.OrderId, cmd.Total));

        await db.SaveChangesAsync();
        // ✓ Order row saved
        // ✓ OutboxMessage row saved  } in one DB transaction
        // ✗ Bus not involved yet
    }
}

4. Add EF migration

dotnet ef migrations add AddOutboxMessages
dotnet ef database update

Architecture

IOutbox (scoped)

Collects messages before SaveChanges. Injected into your service classes.

outbox.Add(new OrderPlaced(orderId, total));     // enqueue
outbox.Add(new PaymentCharged(paymentId, total)); // multiple per save cycle

OutboxInterceptor (scoped SaveChangesInterceptor)

Automatically runs during SaveChanges — no extra code needed after registration. Writes all pending IOutbox messages to the OutboxMessages table within the same database transaction.

OutboxProcessor<TContext> (BackgroundService)

Polls the OutboxMessages table, publishes via IPublishEndpoint, and marks messages as processed. Handles errors per-message — a single failing publish doesn't block the rest of the batch.

OutboxOptions

Property Default Description
PollingInterval 10 seconds How often to check for pending messages
BatchSize 100 Max messages processed per poll cycle

Integration with AutoAudit

Use alongside AutoAudit to get both audit fields and reliable messaging:

[Auditable]
public partial class Order { ... }

// In your service:
db.Orders.Add(order);
outbox.Add(new OrderPlaced(order.Id));
await db.SaveChangesAsync();
// CreatedAt/UpdatedAt set by AuditInterceptor
// OrderPlaced written to OutboxMessages by OutboxInterceptor
// Both in one transaction

Compatibility

Dependency Version
EF Core 8.0+
MassTransit 9.x
.NET net8.0+

License

MIT © 2025 Justin Bannister

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.1 118 6/26/2026
1.0.0 97 6/26/2026

1.0.0: Initial release. Transactional outbox with EF Core SaveChangesInterceptor and MassTransit IPublishEndpoint background processor.