Skip to main content

ZeroAlloc.Outbox

Source-generated transactional outbox for .NET. Annotate a message type with [OutboxMessage] and a Roslyn source generator emits a typed writer and dispatcher bridge — no reflection, no boxing, AOT-safe. Backed by ZeroAlloc.ORM or EF Core (production) or in-memory (tests), with a built-in polling worker, retry, and dead-letter.

Features​

FeatureNotes
Source-generated writers[OutboxMessage] triggers generator; typed IOutboxWriter<T> emitted at compile time
Typed dispatchersIOutboxDispatcher<T> — implement once, wire to any transport (bus, HTTP, email)
ORM storeRaw SQL through ZeroAlloc.ORM on the caller's transaction; SQLite, PostgreSQL or SQL Server
EF Core storeWrites and reads via DbContext; enlist in ambient transaction for atomicity
InMemory storeThread-safe in-process store for unit and integration tests
Polling workerOutboxWorkerService (IHostedService) polls on configurable interval with scope isolation
Lease-based claimClaimPendingAsync atomically leases a batch to one host, so scaling out never double-dispatches a row
Exponential backoffRetry delay = RetryBaseDelay × 2^(attempt-1); configurable via OutboxOptions
Dead-letterEntries that exceed MaxAttempts are dead-lettered with the failure reason
AOT / trimmer safeAll dispatch code is generated; no Type.GetType, no MakeGenericType. AddOutbox() is trim- and AOT-safe; reflection JSON is an explicit opt-in
IOptions<OutboxOptions>Configured through standard Microsoft.Extensions.Options; the worker reads its options once when it starts, so a change takes effect after a restart

Contents​