Interface IIntegrationEvent
- Namespace
- Trellis
- Assembly
- Trellis.Core.dll
Represents an integration event - the stable, published contract a bounded context emits to the outside world (other services or bounded contexts), as distinct from an IDomainEvent which stays inside the context and is raised by aggregates.
public interface IIntegrationEvent
- Extension Methods
Examples
// The external contract - primitive members, no internal domain types.
public sealed record OrderPlacedIntegrationEvent(Guid OrderId, string CustomerEmail, decimal Total, DateTimeOffset OccurredAt)
: IIntegrationEvent;
// Translate a domain event into the integration contract and enqueue it for the outbox.
public sealed class OrderPlacedTranslator(IIntegrationEventCollector collector)
: IDomainEventHandler<OrderPlaced>
{
public ValueTask HandleAsync(OrderPlaced domainEvent, CancellationToken cancellationToken)
{
collector.Add(new OrderPlacedIntegrationEvent(
domainEvent.OrderId.Value,
domainEvent.CustomerEmail.Value,
domainEvent.Total.Amount,
domainEvent.OccurredAt));
return ValueTask.CompletedTask;
}
}
Remarks
Domain events vs. integration events. A domain event is internal: it is raised by
an aggregate, dispatched in-process to IDomainEventHandler<T>, and free to expose the
domain's ubiquitous language because only the owning context observes it. An integration event is
external: it is a versioned wire contract other systems depend on, so it should be deliberately
shaped, stable, and free of internal domain types. Conflating the two leaks internal structure onto
the wire and couples external consumers to refactors of your domain model.
How they relate. Integration events are typically translated from domain
events: a domain-event handler observes a domain event and produces one or more integration events
describing the same business fact in contract terms. Publish them through the transactional outbox
so external delivery is atomic with the state change and survives a crash - see
Trellis.EntityFrameworkCore.Outbox. The outbox relays integration events through
IIntegrationEventPublisher, whose default implementation fans out to in-process
IIntegrationEventHandler<T> registrations and can be replaced with a message-broker
adapter (for example Azure Service Bus or Kafka).
Best practices. Name events in the past tense (for example
OrderPlacedIntegrationEvent); make them immutable; include only contract-relevant data using
primitive or nullable transports rather than internal value objects; treat changes as a versioning
concern; and use OccurredAt as the single timestamp.
Properties
OccurredAt
Gets the timestamp when the business fact this event describes occurred.
DateTimeOffset OccurredAt { get; }
Property Value
- DateTimeOffset
The instant the event was raised, as a DateTimeOffset with an explicit UTC offset. Author it from GetUtcNow() (typically injected) so the canonical UTC offset is recorded and tests can pin time deterministically. DateTimeOffset is preferred over DateTime because the offset round-trips unambiguously through the outbox table and the message bus.