SimpleEventFlow.InMemory 0.1.0

dotnet add package SimpleEventFlow.InMemory --version 0.1.0
                    
NuGet\Install-Package SimpleEventFlow.InMemory -Version 0.1.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="SimpleEventFlow.InMemory" Version="0.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SimpleEventFlow.InMemory" Version="0.1.0" />
                    
Directory.Packages.props
<PackageReference Include="SimpleEventFlow.InMemory" />
                    
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 SimpleEventFlow.InMemory --version 0.1.0
                    
#r "nuget: SimpleEventFlow.InMemory, 0.1.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 SimpleEventFlow.InMemory@0.1.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=SimpleEventFlow.InMemory&version=0.1.0
                    
Install as a Cake Addin
#tool nuget:?package=SimpleEventFlow.InMemory&version=0.1.0
                    
Install as a Cake Tool

SimpleEventFlow

A simple implementation of the event sourcing pattern in C#.

Description

This project demonstrates the basics of event sourcing, where the state of an application is determined by a sequence of events. It includes:

  • Event: A base class for all events.
  • AggregateRoot: An abstract class for aggregate roots, which are entities that handle events and maintain state.
  • EventStore: An in-memory implementation of an event store to persist events.
  • AggregateRepository: A repository to load and save aggregates by applying events.

Features

  • Event sourcing pattern implementation.
  • In-memory event store for simplicity.
  • Easy-to-use aggregate repository for managing aggregates.

Usage

  1. Define Events: Create event classes by inheriting from Event.
  2. Define Aggregates: Create aggregate classes by inheriting from AggregateRoot. Register event handlers and raise events when state changes.
  3. Use Repository: Use AggregateRepository to load and save your aggregates.

Example

Here's a simple example of a bank account using event sourcing.

Events

public class AccountCreatedEvent : Event
{
    public decimal InitialBalance { get; init; }
}

public class DepositMadeEvent : Event
{
    public decimal Amount { get; init; }
}

public class WithdrawalMadeEvent : Event
{
    public decimal Amount { get; init; }
}

Aggregate

public class BankAccount : AggregateRoot
{
    public decimal Balance { get; private set; }

    public BankAccount()
    {
        RegisterHandler<AccountCreatedEvent>(Handle);
        RegisterHandler<DepositMadeEvent>(Handle);
        RegisterHandler<WithdrawalMadeEvent>(Handle);
    }

    private void Handle(AccountCreatedEvent evt)
    {
        Balance = evt.InitialBalance;
    }

    private void Handle(DepositMadeEvent evt)
    {
        Balance += evt.Amount;
    }

    private void Handle(WithdrawalMadeEvent evt)
    {
        Balance -= evt.Amount;
    }

    public void CreateAccount(Guid accountId, decimal initialBalance)
    {
        AggregateId = accountId;
        
        var evt = new AccountCreatedEvent
        {
            EventId = Guid.NewGuid(),
            EventType = nameof(AccountCreatedEvent),
            EventTypeVersion = 1,
            EventOccuredUtc = DateTime.UtcNow,
            AggregateId = accountId,
            AggregateVersion = this.AggregateVersion + 1,
            InitialBalance = initialBalance
        };
        RaiseEvent(evt);
    }

    public void Deposit(decimal amount)
    {
        var evt = new DepositMadeEvent
        {
            EventId = Guid.NewGuid(),
            EventType = nameof(DepositMadeEvent),
            EventTypeVersion = 1,
            EventOccuredUtc = DateTime.UtcNow,
            AggregateId = this.AggregateId ?? throw new InvalidOperationException("AggregateId not set"),
            AggregateVersion = this.AggregateVersion + 1,
            Amount = amount
        };
        RaiseEvent(evt);
    }

    public void Withdraw(decimal amount)
    {
        if (Balance < amount)
            throw new InvalidOperationException("Insufficient funds");

        var evt = new WithdrawalMadeEvent
        {
            EventId = Guid.NewGuid(),
            EventType = nameof(WithdrawalMadeEvent),
            EventTypeVersion = 1,
            EventOccuredUtc = DateTime.UtcNow,
            AggregateId = this.AggregateId ?? throw new InvalidOperationException("AggregateId not set"),
            AggregateVersion = this.AggregateVersion + 1,
            Amount = amount
        };
        RaiseEvent(evt);
    }
}

Using the Repository

var eventStore = new EventStore();
var repository = new AggregateRepository(eventStore);

var accountId = Guid.NewGuid();

// Create account
var account = new BankAccount();
account.CreateAccount(accountId, 100m);
await repository.SaveAggregateAsync(account);

// Load account and make a deposit
var loadedAccount = await repository.GetAggregateAsync<BankAccount>(accountId);
loadedAccount.Deposit(50m);
await repository.SaveAggregateAsync(loadedAccount);

// Load account and make a withdrawal
loadedAccount = await repository.GetAggregateAsync<BankAccount>(accountId);
loadedAccount.Withdraw(30m);
await repository.SaveAggregateAsync(loadedAccount);

Installation

...

Notes

  • This implementation uses an in-memory event store for simplicity. In a production environment, you would want to use a persistent event store.
  • Concurrency control and other advanced features are not implemented in this example.
Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  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

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.0 142 5/4/2025