Why this pattern matters
When an application changes its database and publishes an event, two independent operations can succeed or fail separately. A dual-write vulnerability occurs when the database commit succeeds, but the message broker crashes before receiving the event, resulting in lost messages and inconsistent downstream state.
// Example transactional outbox conceptual flow
await using var transaction = await dbContext.Database.BeginTransactionAsync();
// 1. Persist business state
dbContext.Orders.Add(order);
// 2. Persist integration event in the same transaction
dbContext.OutboxMessages.Add(new OutboxMessage
{
Id = Guid.NewGuid(),
OccurredOn = DateTime.UtcNow,
Type = nameof(OrderCreatedEvent),
Payload = JsonSerializer.Serialize(new OrderCreatedEvent(order.Id))
});
await dbContext.SaveChangesAsync();
await transaction.CommitAsync();
Implementation decisions
In ASP.NET Core with MassTransit, the Entity Framework Core integration automates the outbox table management, background polling, and publisher delivery.