Domain events are the mechanism through which aggregates communicate that something meaningful has happened in the business domain. In MASA Framework, every aggregate root carries an internal event queue. Events are raised by domain methods and dispatched automatically by the Unit of Work when changes are committed — keeping your domain model fully decoupled from the event bus infrastructure.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/masastack/MASA.Framework/llms.txt
Use this file to discover all available pages before exploring further.
Packages
Core Abstractions
IDomainEvent
IDomainEvent extends both IEvent (the base event interface) and ITransaction, meaning every domain event carries an optional IUnitOfWork reference that the framework uses to coordinate commit timing.
DomainEvent
DomainEvent is the abstract record base for all custom domain events. It auto-assigns a new EventId (GUID) and EvenCreateTime (UTC) when instantiated via the default constructor.
DomainCommand
DomainCommand is an abstract record for commands that originate from the domain layer itself (for example, a domain service triggering a side-effect). It shares the same shape as DomainEvent but is semantically a mutation request.
DomainQuery<TResult>
DomainQuery<TResult> is an abstract record for queries dispatched from within the domain. It exposes an abstract Result property where the query handler writes its return value.
IDomainEventBus
IDomainEventBus extends IEventBus with a queue-based dispatch model. When MasaDbContext.SaveChangesAsync() is called, it calls EnqueueAsync for all pending domain events on tracked aggregates. The queue is then flushed during CommitAsync.
| Method | Description |
|---|---|
EnqueueAsync<TDomainEvent>(event) | Adds a domain event to the dispatch queue |
PublishQueueAsync() | Flushes all queued events through the EventBus |
AnyQueueAsync() | Returns true if there are queued events waiting |
Built-in Entity Change Events
MasaDbContext automatically raises structural domain events for every tracked aggregate root when EF Core detects a state change. These require no extra code in your entities.
| Event type | Raised when |
|---|---|
EntityCreatedDomainEvent<TEntity> | An aggregate is in EntityState.Added on save |
EntityModifiedDomainEvent<TEntity> | An aggregate is in EntityState.Modified on save |
EntityDeletedDomainEvent<TEntity> | An aggregate is in EntityState.Deleted on save |
EntityChangedEvent<TEntity> | Base record for all three above types |
Integration Domain Events
For events that must cross service boundaries, extendIntegrationDomainEvent instead of DomainEvent. An integration domain event is both a domain event (handled in-process) and an integration event (published to the message broker via IIntegrationEventBus).
Dispatch Flow
Understanding the flow helps you reason about ordering guarantees:Aggregate raises event
A domain method calls
AddDomainEvent(new MyEvent(...)). The event sits in the aggregate’s _domainEvents list.SaveChangesAsync is called
MasaDbContext.SaveChangesAsync() iterates all tracked IGenerateDomainEvents entries, calls DomainEventBus.EnqueueAsync() for each pending event, and clears the aggregate’s event list.Registration
Code Examples
1 — Define a domain event
2 — Raise from an aggregate
3 — Handle with [EventHandler]
4 — Integration domain event for cross-service scenarios
IntegrationDomainEvent instances are dispatched in-process via IEventBus and published to the message broker via IIntegrationEventBus within the same CommitAsync call. The outbox pattern (if configured) guarantes at-least-once delivery even on process failure.