Shuttle.Recall
21.0.2
Prefix Reserved
dotnet add package Shuttle.Recall --version 21.0.2
NuGet\Install-Package Shuttle.Recall -Version 21.0.2
<PackageReference Include="Shuttle.Recall" Version="21.0.2" />
<PackageVersion Include="Shuttle.Recall" Version="21.0.2" />
<PackageReference Include="Shuttle.Recall" />
paket add Shuttle.Recall --version 21.0.2
#r "nuget: Shuttle.Recall, 21.0.2"
#:package Shuttle.Recall@21.0.2
#addin nuget:?package=Shuttle.Recall&version=21.0.2
#tool nuget:?package=Shuttle.Recall&version=21.0.2
Shuttle.Recall
Shuttle.Recall is an event-sourcing mechanism for .NET that provides a flexible way to persist and retrieve event streams.
Installation
dotnet add package Shuttle.Recall
Registration
To register Shuttle.Recall, use the AddRecall extension method:
services.AddRecall(builder =>
{
builder.AddProjection("ProjectionName", projection =>
{
projection.AddEventHandler<SomeEvent>((context, evt) =>
{
// handle event
});
});
});
The following types are registered:
IEventStore(Scoped): Used to retrieve and save event streams.IEventProcessor(Singleton): Used to process projections.IEventMethodInvoker(Singleton): Invokes event handling methods on aggregate roots.ISerializer(Singleton): Serializes and deserializes events.IConcurrencyExceptionSpecification(Singleton): Detects concurrency exceptions.
Configuration Options
services.AddRecall(options =>
{
options.EventProcessing.ProjectionThreadCount = 5;
options.EventProcessing.IncludedProjections.Add("ProjectionName");
options.EventProcessing.ExcludedProjections.Add("ExcludeMe");
options.EventStore.CompressionAlgorithm = "gzip";
options.EventStore.EncryptionAlgorithm = "aes";
});
EventProcessing Options
| Property | Default | Description |
|---|---|---|
ProjectionThreadCount |
5 |
Number of threads for projection processing |
IncludedProjections |
[] |
List of projection names to include |
ExcludedProjections |
[] |
List of projection names to exclude |
ProjectionProcessorIdleDurations |
varies | Idle durations for processor polling |
EventStore Options
| Property | Default | Description |
|---|---|---|
CompressionAlgorithm |
"" |
Compression algorithm (e.g., "gzip") |
EncryptionAlgorithm |
"" |
Encryption algorithm (e.g., "aes") |
EventHandlingMethodName |
"On" |
Method name invoked on aggregate roots |
BindingFlags |
Instance \| NonPublic |
Binding flags for event method discovery |
Usage
Saving an Event Stream
var eventStore = serviceProvider.GetRequiredService<IEventStore>();
var streamId = Guid.NewGuid();
var stream = await eventStore.GetAsync(streamId);
stream.Add(new SomeEvent { Data = "example" });
await eventStore.SaveAsync(stream);
Saving with Headers
var stream = await eventStore.GetAsync(streamId, builder =>
{
builder.AddHeader("key", "value");
});
stream.Add(new SomeEvent { Data = "example" });
await eventStore.SaveAsync(stream);
Saving with Concurrency Check
var stream = await eventStore.GetAsync(streamId);
stream.Add(new SomeEvent { Data = "example" });
stream.ConcurrencyInvariant(5); // throws EventStreamConcurrencyException if version != 5
await eventStore.SaveAsync(stream);
Saving with Correlation ID
var stream = await eventStore.GetAsync(streamId);
stream
.WithCorrelationId(correlationId)
.Add(new SomeEvent { Data = "example" });
await eventStore.SaveAsync(stream);
Retrieving an Event Stream
var stream = await eventStore.GetAsync(streamId);
// Apply committed events to an aggregate root or state object
stream.Apply(someAggregateRoot);
Retrieving Events by Type
var stream = await eventStore.GetAsync(streamId);
// Get only committed events
var committedEvents = stream.GetEvents(EventStream.EventRegistrationType.Committed);
// Get only appended events
var appendedEvents = stream.GetEvents(EventStream.EventRegistrationType.Appended);
// Get all events
var allEvents = stream.GetEvents(EventStream.EventRegistrationType.All);
Committing Events Before Apply
var stream = await eventStore.GetAsync(streamId);
stream.Add(new SomeEvent { Data = "example" });
// Events are only applied after commit
stream.Commit();
// Now Apply() will include the committed events
stream.Apply(someAggregateRoot);
Removing an Event Stream
var stream = await eventStore.GetAsync(streamId);
stream.Remove();
await eventStore.RemoveAsync(streamId);
Projections
Handler Implementation
Implement the IEventHandler<T> interface to handle events:
public class OrderProjection : IEventHandler<OrderPlaced>
{
public async Task HandleAsync(IEventHandlerContext<OrderPlaced> context, CancellationToken cancellationToken = default)
{
var evt = context.Event;
var projection = context.Projection;
var primitiveEvent = context.PrimitiveEvent;
// Process the event
await SaveToReadModelAsync(evt.OrderId, evt.Amount, cancellationToken);
// Optionally defer for retry
// context.Defer(TimeSpan.FromSeconds(5));
}
}
Registering Projections
services.AddRecall(builder =>
{
builder.AddProjection("OrderProjection", projection =>
{
projection.AddEventHandler<OrderProjection>();
});
});
Inline Projection Handlers
services.AddRecall(builder =>
{
builder.AddProjection("OrderProjection", projection =>
{
projection.AddEventHandler((IEventHandlerContext<OrderPlaced> context) =>
{
var evt = context.Event;
// handle event inline
});
});
});
Delegate-based Handlers
builder.AddProjection("ProjectionName", (IEventHandlerContext<SomeEvent> context) =>
{
// handle event
});
IEventProcessor Lifecycle
var processor = serviceProvider.GetRequiredService<IEventProcessor>();
await processor.StartAsync();
// ... application runs ...
await processor.StopAsync();
EventEnvelope Properties
The EventEnvelope class contains metadata about each event:
| Property | Description |
|---|---|
EventId |
Unique identifier for the event |
EventType |
Full type name of the event |
AssemblyQualifiedName |
Assembly-qualified type name |
Event |
The serialized event bytes |
RecordedAt |
When the event was recorded |
Version |
Event version in the stream |
CorrelationId |
Optional correlation ID |
CompressionAlgorithm |
Compression algorithm used |
EncryptionAlgorithm |
Encryption algorithm used |
Headers |
Custom key-value headers |
EventStream Properties
| Property | Description |
|---|---|
Id |
The stream's unique identifier |
Version |
Current stream version |
CorrelationId |
Correlation ID (if set) |
Removed |
Whether the stream has been removed |
IsEmpty |
Whether the stream has no events |
Count |
Total number of events |
Exceptions
EventStreamConcurrencyException: Thrown when concurrent modification is detectedEventProcessingException: Thrown during projection event processing failures
Documentation
Please visit the Shuttle.Recall documentation for more information.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.Hosting (>= 10.0.5)
- Microsoft.Extensions.Logging (>= 10.0.5)
- Shuttle.Contract (>= 21.0.1)
- Shuttle.Pipelines (>= 21.0.1)
- Shuttle.Reflection (>= 21.0.1)
- Shuttle.Serialization (>= 21.0.1)
- Shuttle.Specification (>= 21.0.1)
- Shuttle.Streams (>= 21.0.1)
- Shuttle.Threading (>= 21.0.1)
NuGet packages (12)
Showing the top 5 NuGet packages that depend on Shuttle.Recall:
| Package | Downloads |
|---|---|
|
Shuttle.Recall.Sql.Storage
Sql-based implementation of the event store Shuttle.Recall persistence interfaces. |
|
|
Shuttle.Esb.Process
Shuttle.Esb process management using Shuttle.Recall event sourcing. |
|
|
Shuttle.Recall.Tests
Tests to exercise Shuttle.Recall component implementations. |
|
|
Shuttle.Recall.Sql.EventProcessing
Sql-based implementation of the event store Shuttle.Recall projection interfaces. |
|
|
Shuttle.Access.Sql
Provides Sql-based implementation of data access components for use with Shuttle.Access implementations. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 21.0.2 | 26 | 4/15/2026 |
| 21.0.2-rc3 | 99 | 4/11/2026 |
| 21.0.2-rc2 | 127 | 3/21/2026 |
| 21.0.2-rc1 | 89 | 3/21/2026 |
| 21.0.1-rc1 | 104 | 2/28/2026 |
| 21.0.1-beta | 119 | 2/7/2026 |
| 21.0.0-alpha | 108 | 1/18/2026 |
| 20.0.0 | 1,925 | 2/2/2025 |
| 18.0.0 | 569 | 8/5/2024 |
| 17.0.1 | 641 | 5/3/2024 |
| 17.0.0 | 591 | 4/30/2024 |
| 16.1.1 | 3,953 | 12/1/2022 |
| 16.0.0 | 4,168 | 9/4/2022 |
| 14.0.0 | 3,240 | 5/29/2022 |
| 13.1.0 | 2,909 | 5/6/2022 |
| 13.0.1 | 4,606 | 4/9/2022 |
| 13.0.0 | 3,150 | 3/21/2022 |
| 12.0.5 | 723 | 1/22/2022 |
| 12.0.3 | 3,282 | 2/4/2021 |