Skip to content

Storing and Reading Events

Once EventSourcingKit is registered, you interact with the event store through IEventStore. You inject it like any other service, then store new events and read existing ones back.

Storing an Event

To store an event, you wrap it in an EventCandidate and assign it a Subject – the path that identifies the entity the event belongs to. A subject always starts with a slash:

using EventSourcingKit;
using EventSourcingKit.Store;

public class LibraryService(IEventStore eventStore)
{
    public async Task RegisterBook(
        Guid bookId,
        string title,
        string author,
        CancellationToken cancellationToken
    )
    {
        var subject = new Subject($"/books/{bookId}");
        var candidate = new EventCandidate(
            subject,
            new BookRegistered(bookId, title, author)
        );

        await eventStore.StoreEvent(
            candidate,
            [new IsSubjectPristinePrecondition(subject)],
            cancellationToken
        );
    }
}

You do not pass the event type name when storing – EventSourcingKit derives it from the [EventType] attribute on your event. Use StoreEvent for a single event, or StoreEvents to store several atomically.

Guarding Writes with Preconditions

The second argument is a list of preconditions – conditions that must hold for the write to succeed. They give you optimistic concurrency and let you enforce business rules at the store level. Here, IsSubjectPristinePrecondition ensures the book does not already exist: if any event has been stored under the subject, the write is rejected.

Reading Events

To read events back, call GetEvents with a subject. It returns an asynchronous stream you iterate with await foreach:

await foreach (var @event in eventStore.GetEvents(
    new Subject($"/books/{bookId}"),
    cancellationToken: cancellationToken
))
{
    Console.WriteLine($"{@event.Id}: {@event.Type}");
}

Each Event carries its metadata – Id, Time, Type, Subject – alongside the typed Data payload, and the events arrive in the order they were stored. That ordered stream is exactly what you need to rebuild state.

For More Information