Skip to content

Pragmatic.Events

Domain events for .NET 10 — raise, dispatch, and handle with zero ceremony, including an EF Core interceptor for automatic post-SaveChanges dispatch.

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 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.

Terminal window
dotnet add package Pragmatic.Events
dotnet add package Pragmatic.Events.EFCore # post-SaveChanges interceptor dispatch

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 |

  • .NET 10.0+

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).