EventSourcingDotNet 0.27.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package EventSourcingDotNet --version 0.27.0
                    
NuGet\Install-Package EventSourcingDotNet -Version 0.27.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="EventSourcingDotNet" Version="0.27.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="EventSourcingDotNet" Version="0.27.0" />
                    
Directory.Packages.props
<PackageReference Include="EventSourcingDotNet" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add EventSourcingDotNet --version 0.27.0
                    
#r "nuget: EventSourcingDotNet, 0.27.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package EventSourcingDotNet@0.27.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=EventSourcingDotNet&version=0.27.0
                    
Install as a Cake Addin
#tool nuget:?package=EventSourcingDotNet&version=0.27.0
                    
Install as a Cake Tool

EventSourcingDotNet

Event Sourcing made easy

Event Store Providers

Snapshot Providers

  • In-Memory

Getting Started

Define your aggregate state and ID

Aggregate ID

Create a readonly ID record struct for each of your aggregates.

It must implement the IAggregateId interface to be accepted as an aggregate ID.

The static AggregateName property and the AsString() method are used to compose the stream name. You should not use dashes in your AggregateName because some providers, e.g. Event Store DB, will split the stream name at the first dash to provide a by-category stream.

public readonly record struct MyAggregateId(Guid Id) : IAggregateId
{
    public static string AggregateName => "myAggregate";

    public string AsString() => Id.ToString();
}

Aggregate State

Create a state record representing the current state of your aggregate.

It must implement the generic IAggregateState<TAggregatId> interface to be accepted as an aggregate state. The generic type argument TAggregateId is the aggregate ID specified above.

public sealed record MyAggregate : IAggregateState<MyAggregateId>
{
    public int MyValue { get; init; }
}
Aggregate State Rules
  • The state record should be immutable.
    Some storage or snapshot providers, e.g. the In-Memory snapshot provider, may keep a reference to the latest version of the aggregate. Mutations of the aggregate state may lead to an inconsistent aggregate state.

  • The state record must provide a public parameterless constructor.
    To create a new instance of the

Define your events

Create a record for each and every event happening on your aggregate. An event must implement the IDomainEvent<TAggregateId, TState> interface to be accepted as a valid event.

Each event must implement the Apply(TState) method to update the aggregate state.

public sealed record SomethingHappened : IDomainEvent<SomeState>
{
    public Something Apply(SomeState state)
    {
        // return updated state here
    }
}

Event validation

The IDomainEvent<TAggregateId, TState> interface provides an additional Validate method allowing to implement logic whether an event should be fired, skipped or raise an error. The validation happens before the event is applied to the aggregate state and added to the uncommitted events.

public sealed record SomethingHappened : IDomainEvent<SomeState>
{
    // Apply method removed for brevity

    public EventValidationResult Validate(SomeState state)
    {
        // do some validation logic here...
        return EventValidationResult.Fire;
    }
}

You can return the following validation results:

  • EventValidationResult.Fire
    The event will be applied to the aggregate state and added to the uncommitted events collection.

  • EventValidationResult.Skip
    The event will be skipped. It will not be applied to the aggregate state and not added to the uncommitted events collection.
    Use this validation result when the aggregate state will not be affected by the event and you want to avoid extra effect-less events in the event stream

  • EventValidationResult.Fail(Exception)
    The event cannot be applied in the current state of the aggregate or it would lead to an inconsistent state.
    The method takes an Exception parameter which expresses why this event cannot be applied.

Define update logic

Aggregates are updated by getting the current version from the aggregate repository, adding some new events and then saving the aggregate back to the event store.

Avoid to run long running tasks after getting the aggregate from the repository and storing it back as it increases the risk of running into a concurrency issue.
All Event Store providers use optimistic concurrency checks to avoid update conflicts.

private readonly IAggregateRepository<SomeId, SomeState> _repository;

public async Task DoSomething(SomeRequest request)
{
    var aggregate = await _repository.GetByIdAsync(request.Id);

    aggregate = aggregate.AddEvent(new SomethingHappened());

    await _repository.SaveAsync(aggregate);
}

Alternatively there is a shorthand extension method allowing to retrieve, update and save the aggregate in one statement:

IAggregateRepository<TAggregateId, TState>.UpdateAsync(TAggregateId aggregateId, params IDomainEvent<TState>[] events);
    
Product Compatible and additional computed target framework versions.
.NET net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (6)

Showing the top 5 NuGet packages that depend on EventSourcingDotNet:

Package Downloads
EventSourcingDotNet.InMemory

In-Memory provider for EventSourcingDotNet

EventSourcingDotNet.EventStore

EventStoreDB provider for EventSourcingDotNet

EventSourcingDotNet.Serialization.Json

JSON Serialization implementation for EventSourcingDotNet

EventSourcingDotNet.FileStorage

Package Description

EventSourcingDotNet.KurrentDB

KurrentDB provider for EventSourcingDotNet

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.3.0-pre.0.1 84 8/21/2025
1.2.3-pre.0.2 10 8/25/2025
1.2.3-pre.0.1 12 8/25/2025
1.2.2 15 8/25/2025
1.2.2-pre.0.2 65 8/22/2025
1.2.2-pre.0.1 89 8/21/2025
1.2.1 88 8/21/2025
1.2.0 89 8/21/2025
1.2.0-pre.0.8 85 8/21/2025
1.2.0-pre.0.1 441 7/21/2025
1.1.0 149 7/16/2025
1.1.0-pre.0.1 117 7/16/2025
1.1.0-pre.0 113 7/16/2025
1.0.0 136 7/16/2025
1.0.0-rc1.17 85 7/11/2025
1.0.0-rc1.16 86 7/11/2025
1.0.0-rc1.15 128 5/25/2025
1.0.0-rc1.14 128 5/25/2025
1.0.0-rc1.6 134 8/12/2023
1.0.0-rc1.5 123 8/12/2023
1.0.0-rc1 281 4/4/2023
0.31.0-pre.0.43 150 4/4/2023
0.31.0-pre.0.40 154 4/2/2023
0.31.0-pre.0.39 142 3/30/2023
0.31.0-pre.0.37 147 3/30/2023
0.31.0-pre.0.35 158 3/28/2023
0.31.0-pre.0.33 157 3/28/2023
0.31.0-pre.0.23 160 3/28/2023
0.31.0-pre.0.22 154 3/5/2023
0.31.0-pre.0.20 159 3/4/2023
0.31.0-pre.0.17 151 3/4/2023
0.31.0-pre.0.15 227 2/16/2023
0.31.0-pre.0.13 145 2/16/2023
0.31.0-pre.0.10 157 2/15/2023
0.31.0-pre.0.7 159 2/15/2023
0.31.0-pre.0.6 175 1/30/2023
0.31.0-pre.0.5 179 1/4/2023
0.31.0-pre.0.4 165 1/4/2023
0.31.0-pre.0.3 167 1/4/2023
0.31.0-pre.0.1 171 1/4/2023
0.30.1 573 1/4/2023
0.30.0 427 12/30/2022
0.30.0-pre.0.12 161 12/30/2022
0.30.0-pre.0.9 160 12/13/2022
0.30.0-pre.0.8 166 12/11/2022
0.30.0-pre.0.2 157 12/9/2022
0.29.1-pre.0.1 154 12/9/2022
0.29.0 431 12/8/2022
0.29.0-pre.0.52 155 12/8/2022
0.29.0-pre.0.51 154 12/8/2022
0.29.0-pre.0.43 159 12/4/2022
0.29.0-pre.0.42 159 12/4/2022
0.29.0-pre.0.41 164 11/27/2022
0.29.0-pre.0 159 11/24/2022
0.28.0 443 11/22/2022
0.27.0 434 11/20/2022
0.26.0 461 11/20/2022
0.25.0 526 11/20/2022