Reference implementation of the Outbox / Inbox transactional-messaging pattern in .NET — a standalone study project built to internalize distributed-systems design end-to-end, beyond what tutorials typically cover.
The Outbox pattern solves the dual-write problem: a service must atomically persist a state change and publish a domain event, but DB.Save() and MessageBroker.Publish() are not in the same transaction. Without the pattern, a crash between the two leaves the system inconsistent.
The fix:
- Inside the database transaction, write the event row to an outbox table alongside the business data.
- A background publisher polls the outbox table, dispatches each event to the message broker, and marks it sent.
- The receiving service uses an inbox table to deduplicate (idempotency) — events received twice are processed once.
The result: at-least-once delivery with idempotent consumption, all without distributed transactions.
Order.API Stock.Service
┌─────────────────────────────┐ ┌────────────────────────┐
│ BEGIN TX │ │ │
│ INSERT order │ │ receives event │
│ INSERT into outbox_table │ │ check inbox_table │
│ COMMIT │ │ (dedup) │
│ │ │ insert inbox row + │
└─────────────────────────────┘ │ process business │
│ └────────────────────────┘
▼ ▲
┌─────────────────────────────┐ │
│ Order.Outbox.Table. │ ── publish event ─────▶ RabbitMQ ──────┘
│ Publisher.Service │
│ (background polling worker)│
└─────────────────────────────┘
| Layer | Technology |
|---|---|
| Runtime | .NET / ASP.NET Core |
| Persistence | Entity Framework Core + outbox / inbox tables |
| Background | BackgroundService polling publisher |
| Broker | RabbitMQ (MassTransit) |
| Pattern | Outbox + Inbox + idempotent consumer |
.
├── Order.API/ # Writes to DB + outbox in one TX
├── Order.Outbox.Table.Publisher.Service/ # Background publisher (polls outbox)
├── Stock.Service/ # Consumer with inbox-based dedup
├── Shared/ # Event contracts
└── Microservices.Outbox.Inbox.Design.Pattern.sln
The Outbox pattern is one of the most-used patterns in real distributed systems (Microsoft, Stripe, Uber all use variants). It's a prerequisite for any reliable event-driven architecture where you can't afford to lose or duplicate events.
Built by Ali Kalantari — a Backend Developer specialising in regulated fintech systems (.NET, Python, multi-database, event-driven).
This repository is part of my Distributed Systems Reference Series: a set of standalone study projects, each focused on one pattern, that I keep as working references when implementing similar designs in production.
Browse the full series: github.com/Ali-Klnai?tab=repositories&q=Microservices.