Event Source ID
Event Source ID is a fundamental concept in Chronicle that identifies the source of events. In the Application Model client, event source IDs are automatically resolved and managed to provide seamless integration within command handlers.
How Event Source ID Resolution Works
The Application Model client uses the EventSourceValuesProvider to automatically determine the event source ID for commands. This process follows a specific resolution strategy:
Resolution Strategy
- ICanProvideEventSourceId Interface: If a command implements
ICanProvideEventSourceId, it will use the provided event source ID - Property Detection: The system looks for properties of type
EventSourceIdor properties marked with[Key]attribute - Tuple Support: For tuple-based responses, it searches for
EventSourceIdvalues within the tuple - Auto-generation: If no event source ID is found, a new one is automatically generated
ICanProvideEventSourceId Interface
Commands can explicitly provide their event source ID by implementing the ICanProvideEventSourceId interface:
public record UpdateUserCommand(Guid UserId, string Name) : ICanProvideEventSourceId
{
public EventSourceId GetEventSourceId() => UserId.ToString();
}
```This approach gives you full control over how the event source ID is determined for your command.
## Property-Based Resolution
### EventSourceId Property
The simplest approach is to have a property of type `EventSourceId` in your command:
```csharp
public record CreateOrderCommand(EventSourceId OrderId, string CustomerName, decimal Amount);
Key Attribute
You can also mark a property with the [Key] attribute to indicate it should be used as the event source ID:
public record UpdateProductCommand([Key] Guid ProductId, string Name, decimal Price);
Tuple-Based Resolution
When returning tuples from command handlers, the system will search for EventSourceId values within the tuple:
public record CreateProductCommand(string Name, decimal Price)
{
public (ProductCreated, EventSourceId) Handle()
{
var productId = EventSourceId.New();
var productCreated = new ProductCreated
{
Name = Name,
Price = Price
};
return (productCreated, productId);
}
}
```## Automatic Generation
If no event source ID can be resolved from the command, the system will automatically generate a new one using `EventSourceId.New()`. This is useful for creation scenarios where the ID is not known beforehand.
## EventSourceValuesProvider
The `EventSourceValuesProvider` is responsible for the resolution logic. It implements `ICommandContextValuesProvider` and is automatically registered with the dependency injection container.
### Implementation Details
The provider follows this logic:
1. Check if the command implements `ICanProvideEventSourceId`
2. If not, check if the command has an event source ID using `HasEventSourceId()` extension method
3. Extract the event source ID using `GetEventSourceId()` extension method
4. If none found, generate a new event source ID
## Command Context Integration
Once resolved, the event source ID is stored in the `CommandContext` under the well-known key `WellKnownCommandContextKeys.EventSourceId`. This makes it available throughout the command processing pipeline.
You can access the event source ID in your command handlers using:
```csharp
public record ProcessOrderCommand([Key] Guid OrderId)
{
public object Handle(CommandContext commandContext)
{
var eventSourceId = commandContext.GetEventSourceId();
// Use the event source ID for processing
return new OrderProcessed();
}
}
Error Handling
If an event source ID cannot be resolved when needed (for example, when accessing aggregate roots or read models), the following exceptions may be thrown:
MissingEventSourceIdInCommandContext: When trying to access an event source ID that hasn't been set in the command contextUnableToResolveAggregateRootFromCommandContext: When trying to resolve an aggregate root without a valid event source IDUnableToResolveReadModelFromCommandContext: When trying to resolve a read model without a valid event source ID
Best Practices
- Be Explicit: When possible, implement
ICanProvideEventSourceIdor useEventSourceIdproperties for clarity - Consistent Naming: Use consistent property names like
Id,EntityId, or[Entity]Idfor key properties - Validation: Ensure event source IDs are valid before processing commands
- Documentation: Document which property serves as the event source ID in your commands
Examples
Creation Command
public record CreateUserCommand(string Email, string Name);
// Event source ID will be auto-generated
Update Command with Key
public record UpdateUserCommand([Key] Guid UserId, string Name);
Command with Explicit Event Source ID
public record ActivateUserCommand(EventSourceId UserId);
Custom Event Source ID Provider
public record TransferFundsCommand(Guid FromAccountId, Guid ToAccountId, decimal Amount) : ICanProvideEventSourceId
{
public EventSourceId GetEventSourceId() => FromAccountId.ToString();
}