Pragmatic.Events
Domain events for .NET 10 — raise, dispatch, and handle with zero ceremony, including an EF Core
interceptor for automatic post-SaveChanges dispatch.
The Problem
Section titled “The Problem”As modules grow they need to react to each other. Confirm a reservation and billing must invoice, notifications must email, audit must log. Direct calls couple the entity to every downstream service, force you to edit the entity for each new reaction, and let a non-critical failure (email) break the core operation.
public async Task ConfirmAsync(){ Status = ReservationStatus.Confirmed; await _billing.CreateDraftInvoiceAsync(Id, GuestId, TotalAmount, Currency); await _notifications.SendConfirmationEmailAsync(GuestId, Id); // failure here breaks confirm}The Solution
Section titled “The Solution”The entity raises an event describing what happened; handlers in other boundaries subscribe and react independently — no coupling, no edits when a new consumer appears, and isolated failure handling.
public VoidResult<IError> Confirm(){ var result = TransitionTo(ReservationStatus.Confirmed); if (result.IsSuccess) RaiseEvent(new ReservationConfirmed(Id, GuestId, PropertyId)); return result;}
public sealed class CreateInvoiceOnConfirm : IDomainEventHandler<ReservationConfirmed>{ public Task HandleAsync(ReservationConfirmed e, CancellationToken ct) => /* ... */;}Handlers are discovered automatically; the EF Core interceptor dispatches after a successful
SaveChanges. Ordering and continue-on-failure are built in. When you need crash-safe, at-least-once
delivery, enable the transactional outbox — it ships in the Pragmatic.Events.EFCore package
(namespace Pragmatic.Events.EFCore.Outbox), not Pragmatic.Messaging. Add
Messaging only for cross-service delivery over a broker.
Installation
Section titled “Installation”dotnet add package Pragmatic.Eventsdotnet add package Pragmatic.Events.EFCore # post-SaveChanges interceptor dispatchStatus
Section titled “Status”Raise/dispatch/handle, handler ordering, continue-on-failure, declarative lifecycle events
([Raises<T>]), the EF Core interceptor, and the transactional outbox are functional within
1.0.0-alpha. The outbox currently requires manual wiring on a hand-written DbContext (no declarative
opt-in on a source-generated DbContext yet). See the roadmap.
| Concepts | Raise/subscribe model, dispatch timing, ordering, transactional outbox |
| Getting Started | Raise an event, write a handler, wire the interceptor, lifecycle [Raises<T>], outbox |
| Internals | Interceptor lifecycle, typed dispatch table, outbox mechanics, observability |
| Common Mistakes | The most frequent event pitfalls |
| Troubleshooting | Problem/solution guide |
Requirements
Section titled “Requirements”- .NET 10.0+
License
Section titled “License”Part of the Pragmatic.Design ecosystem — see Licensing. Pragmatic.Events is licensed under the PolyForm Small Business 1.0.0 license (free for small businesses; commercial license above the threshold).