Skip to content

Projection with event context values

Event context contains metadata about each event, such as when it occurred, its sequence number, and causation information. Projections can access these values to enrich read models with event metadata.

The EventContext contains the following properties you can map to:

  • EventSourceId - The identifier of the event source that produced the event
  • SequenceNumber - The position of the event in the event sequence
  • Occurred - When the event occurred (timestamp)
  • EventType - Information about the event type
  • EventSourceType - The type of the event source
  • EventStreamType - The type of the event stream
  • EventStreamId - The identifier of the event stream
  • CorrelationId - The correlation identifier linking related operations
  • Causation - Information about what caused this event
  • CausedBy - Identity information about who caused the event

Use ToEventSourceId() to map the event source ID to a property:

using Cratis.Chronicle.Projections;
public class DecEventContextUserActivityProjection : IProjectionFor<DecEventContextUserActivity>
{
public void Define(IProjectionBuilderFor<DecEventContextUserActivity> builder) => builder
.From<DecEventContextUserLoggedIn>(_ => _
.Set(m => m.UserId).ToEventSourceId()
.Set(m => m.LastLogin).ToEventContextProperty(c => c.Occurred))
.From<DecEventContextUserPerformedAction>(_ => _
.Set(m => m.UserId).ToEventSourceId()
.Set(m => m.LastActivity).ToEventContextProperty(c => c.Occurred));
}

Use ToEventContextProperty() to map any event context property:

using Cratis.Chronicle.Events;
using Cratis.Chronicle.Projections;
[EventType]
public record DecEventContextUserAction(string UserId, string ActionType);
public class DecEventContextAuditTrailProjection : IProjectionFor<DecEventContextAuditEntry>
{
public void Define(IProjectionBuilderFor<DecEventContextAuditEntry> builder) => builder
.AutoMap()
.From<DecEventContextUserAction>(_ => _
.Set(m => m.EventId).ToEventContextProperty(c => c.SequenceNumber)
.Set(m => m.OccurredAt).ToEventContextProperty(c => c.Occurred)
.Set(m => m.CorrelationId).ToEventContextProperty(c => c.CorrelationId));
}

Your read models can include properties for event metadata:

public record DecEventContextUserActivity(
string UserId,
DateTimeOffset LastLogin,
DateTimeOffset LastActivity);
public record DecEventContextAuditEntry(
ulong EventId,
DateTimeOffset OccurredAt,
string CorrelationId,
string ActionType,
string UserId);

Event context properties can be part of composite keys:

using Cratis.Chronicle.Events;
using Cratis.Chronicle.Projections;
[EventType]
public record DecEventContextUserActionForKey(string UserId, string ActionType);
public record DecEventContextEventLogKey(DateTimeOffset Date, ulong SequenceNumber);
public record DecEventContextEventLogEntry(
DecEventContextEventLogKey Id,
string ActionType,
string UserId);
public class DecEventContextEventLogProjection : IProjectionFor<DecEventContextEventLogEntry>
{
public void Define(IProjectionBuilderFor<DecEventContextEventLogEntry> builder) => builder
.From<DecEventContextUserActionForKey>(_ => _
.UsingCompositeKey<DecEventContextEventLogKey>(_ => _
.Set(k => k.Date).ToEventContextProperty(c => c.Occurred)
.Set(k => k.SequenceNumber).ToEventContextProperty(c => c.SequenceNumber))
.Set(m => m.ActionType).To(e => e.ActionType)
.Set(m => m.UserId).To(e => e.UserId));
}

Event context properties work in child collections and joins:

using Cratis.Chronicle.Events;
using Cratis.Chronicle.Projections;
[EventType]
public record DecEventContextActivityPerformed(string ActivityId, string ActivityType);
public record DecEventContextActivityLogEntry(
string ActivityId,
DateTimeOffset Timestamp,
ulong SequenceNumber);
public record DecEventContextUserWithActivityLog(
IEnumerable<DecEventContextActivityLogEntry> ActivityLog);
public class DecEventContextUserActivityLogProjection : IProjectionFor<DecEventContextUserWithActivityLog>
{
public void Define(IProjectionBuilderFor<DecEventContextUserWithActivityLog> builder) => builder
.Children(m => m.ActivityLog, children => children
.IdentifiedBy(e => e.ActivityId)
.AutoMap()
.From<DecEventContextActivityPerformed>(_ => _
.UsingKey(e => e.ActivityId)
.Set(m => m.Timestamp).ToEventContextProperty(c => c.Occurred)
.Set(m => m.SequenceNumber).ToEventContextProperty(c => c.SequenceNumber)));
}
using Cratis.Chronicle.Events;
[EventType]
public record DecEventContextUserLoggedIn(string Username);
[EventType]
public record DecEventContextUserPerformedAction(string UserId, string ActionType);

Map Occurred, SequenceNumber, and CausedBy for complete audit information.

Include CorrelationId to trace related operations across services.

Use Occurred for time-series analysis and historical reporting.

Use SequenceNumber when you need to preserve exact event ordering.

Use EventSourceId to identify which event source produced the event.

Event context properties provide rich metadata that can significantly enhance your read models with timing, traceability, and debugging information.