PostgreSQL implementation of IDatabase / IUnitOfWork with transactional outbox support.
// Program.cs
builder.AddAzureNpgsqlDataSource("Postgres"); // Aspire resource name
builder.Services
.AddPostgresDatabase()
.AddPostgresUnitOfWork()
.AddPostgresOutboxPublisher() // transactional outbox publisher
.AddDbContext<MyDbContext>()
.AddEfDb<MyEfDb>();Functions/procedures raise SQLSTATE values to signal domain exceptions — no application-layer switch statements.
| SQLSTATE | CoreEx exception |
|---|---|
| 56001 | ValidationException |
| 56002 | BusinessException |
| 56004 | ConcurrencyException |
| 56005 | NotFoundException |
| 56006 | ConflictException |
| 56007 | DuplicateException |
PostgresOutboxPublisher writes events to the outbox table within the current TransactionAsync scope. The PostgresOutboxRelayHostedService polls and forwards them to IEventPublisher (typically Azure Service Bus).
// Relay host Program.cs
builder.Services
.AddPostgresDatabase()
.AddPostgresUnitOfWork()
.AddPostgresOutboxRelay();
builder.AddPostgresOutboxRelayHostedService(); // called on builder, not builder.Servicesbuilder.WithCoreExTelemetry()
.WithCoreExPostgresTelemetry()
.UseOtlpExporter();- Do not mix
UseExpectedSqlServerOutboxPublisher/ExpectSqlServerOutboxEventsin tests for a Postgres-backed domain — use the Postgres equivalents. - Do not call
AddPostgresOutboxRelayHostedService()onbuilder.Services— call it onbuilder.
- README — full API reference including
PostgresDatabase, metrics, and Npgsql extensions. - CoreEx.Database — abstract base types.
- Infrastructure layer — PostgreSQL-specific repository, mapper, and outbox wiring in the Products sample.
- Tooling —
*.Databaseproject (DbEx) for PostgreSQL schema generation and outbox infrastructure setup.