Skip to content

Latest commit

 

History

History
 
 

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Simple, practical EventSourcing with EventStoreDB and EntityFramework

The is the simple Event Sourcing setup with EventStoreDB. For the Read Model, Postgres and Entity Framework are used.

You can watch the webinar on YouTube where I'm explaining the details of the implementation:

Practical introduction to Event Sourcing with EventStoreDB

or read the article explaining the read model part: "How to build event-driven projections with Entity Framework"

Main assumptions:

  • explain basics of Event Sourcing, both from the write model (EventStoreDB) and read model part (Postgres and EntityFramework),
  • CQRS architecture sliced by business features, keeping code that changes together at the same place. Read more in How to slice the codebase effectively?
  • no aggregates, just data (records) and functions,
  • clean, composable (pure) functions for command, events, projections, query handling instead of marker interfaces (the only one used internally is IEventHandler). Thanks to that testability and easier maintenance.
  • easy to use and self-explanatory fluent API for registering commands and projections with possible fallbacks,
  • registering everything into regular DI containers to integrate with other application services.
  • pushing the type/signature enforcement on edge, so when plugging to DI.

Overview

It uses:

  • pure data entities, functions and handlers,
  • Stores events from the command handler result EventStoreDB,
  • Builds read models using Subscription to $all.
  • Read models are stored to Postgres relational tables with Entity Framework.
  • App has Swagger and predefined docker-compose to run and play with samples.

Write Model

  • Sample ShoppingCart entity and events represent the business workflow. All are stored in the same file to be able to understand flow without jumping from one file to another. It also contains When method defining how to apply events to get the entity state. It uses the C#9 switch syntax with records deconstruction.
  • Example ProductItemsList value object wrapping the list of product items in the shopping carts. It simplified the main state apply logic and offloaded some of the invariants checks.
  • All commands by convention should be created using the factory method to enforce the types,
  • Command handlers are defined as static methods in the same file as command definition. Usually, they change together. They are pure functions that take command and/or state and create new events based on the business logic. See sample Adding Product Item to ShoppingCart. This example also shows that you can inject external services to handlers if needed.
  • Added syntax for self-documenting command handlers registration. See the details of registration in CommandHandlerExtensions. They differentiate case when a new entity/stream is created from the update case. Update has to support optimistic concurrency. Added also Command Handlers Builder for simplifying the registrations.
  • Added simple EventStoreDB extensions repository to load entity state and store event created by business logic,

Read Model

Tests

API integration tests for:

Prerequisites

  1. Install git - https://git-scm.com/downloads.
  2. Install .NET 6.0 - https://dotnet.microsoft.com/download/dotnet/6.0.
  3. Install Visual Studio 2022, Rider or VSCode.
  4. Install docker - https://docs.docker.com/engine/install/.
  5. Open ECommerce.sln solution.

Running

  1. Go to docker and run: docker-compose up.
  2. Wait until all dockers got are downloaded and running.
  3. You should automatically get:
    • EventStoreDB UI (for event store): http://localhost:2113/
    • Postgres DB running (for read models)
    • PG Admin - IDE for postgres. Available at: http://localhost:5050.
      • Login: admin@pgadmin.org, Password: admin
      • To connect to server Use host: postgres, user: postgres, password: Password12!
  4. Open, build and run ECommerce.sln solution.