Resolving EventSourceId
Chronicle resolves an EventSourceId anywhere it needs an identity for an aggregate, event append, or read model lookup. The same conventions work whether the value comes from a command record or from query arguments bound from the HTTP request.
For details on how Chronicle stores resolved values in the command pipeline, see Command Context Values.
Why Chronicle Resolves EventSourceId
Chronicle needs an event source id to:
- append events to the correct event source
- load aggregate roots for model-bound commands
- resolve read models used in command handlers and validators
- match read model queries to a specific aggregate identity
Resolution Order for Commands
When Chronicle inspects a command, it resolves the event source id in this order:
- Implement
ICanProvideEventSourceIdand return the id fromGetEventSourceId(). - Add a property whose type is
EventSourceIdor derives from it. - Mark a property with
[Key]and let Chronicle convert that value toEventSourceId.
If none of these are present, Chronicle creates a new EventSourceId so automatic event appends still have a valid identity.
using Cratis.Arc.Commands;
using Cratis.Arc.Chronicle.Commands;
using Cratis.Chronicle.Events;
using Cratis.Chronicle.Keys;
[Command]
public record OpenAccount(Guid AccountId, string OwnerName) : ICanProvideEventSourceId
{
public EventSourceId GetEventSourceId() => AccountId.ToString();
}
[Command]
public record RenameAccount(EventSourceId AccountId, string NewName);
[Command]
public record CloseAccount([Key] Guid AccountId);
Resolution for Query Arguments
Chronicle uses the same identity conventions when you pass arguments to query methods that target a specific read model instance. In practice this usually means:
- an argument of type
EventSourceId - an argument of a type that derives from
EventSourceId - an argument or bound property marked with
[Key]
Those arguments can come from route parameters, query string parameters, or request bodies through Arc's normal query binding rules.
using Cratis.Arc.Queries.ModelBound;
using Cratis.Chronicle.Events;
using Cratis.Chronicle.Keys;
using MongoDB.Driver;
[ReadModel]
public record CustomerOverview(EventSourceId Id, string Name)
{
public static CustomerOverview? ById(
EventSourceId id,
IMongoCollection<CustomerOverview> collection) =>
collection.Find(_ => _.Id == id).FirstOrDefault();
public static CustomerOverview? ByLegacyId(
[Key] Guid customerId,
IMongoCollection<CustomerOverview> collection) =>
collection.Find(_ => _.Id == customerId.ToString()).FirstOrDefault();
}
Read Models and Aggregate Roots
When you inject a read model or aggregate root into a model-bound command, Chronicle uses the resolved event source id from the current command context to load the correct instance.
For command-specific guidance, see: