Skip to content

Commit 1a3f47f

Browse files
committed
Added Updated Readmes, Removed old slides
1 parent fd7b53f commit 1a3f47f

11 files changed

+228
-113
lines changed

EventSourcing.NetCore.sln

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,9 @@ EndProject
205205
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Api.Testing", "Core.Api.Testing\Core.Api.Testing.csproj", "{825A40DB-5AB5-4565-AADB-28AC760D0A43}"
206206
EndProject
207207
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Simple", "Simple", "{11DD4963-5BB4-4E1B-9475-8EB10C822BFC}"
208+
ProjectSection(SolutionItems) = preProject
209+
Sample\EventStoreDB\Simple\README.md = Sample\EventStoreDB\Simple\README.md
210+
EndProjectSection
208211
EndProject
209212
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ECommerce.Api", "Sample\EventStoreDB\Simple\ECommerce.Api\ECommerce.Api.csproj", "{414D1D34-1002-4159-B738-DF3EE042F9FD}"
210213
EndProject

README.md

Lines changed: 146 additions & 113 deletions
Large diffs are not rendered by default.

Sample/EventStoreDB/Simple/ECommerce.sln

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Api.Testing", "..\..\.
1414
EndProject
1515
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ECommerce.Core", "ECommerce.Core\ECommerce.Core.csproj", "{3DF5E171-72BD-4129-B66C-5428029CF932}"
1616
EndProject
17+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{6C654A81-F8CF-46DE-9CD8-442162F3F6FD}"
18+
ProjectSection(SolutionItems) = preProject
19+
README.md = README.md
20+
EndProjectSection
21+
EndProject
1722
Global
1823
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1924
Debug|Any CPU = Debug|Any CPU
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Simple, practical EventSourcing with EventStoreDB and EntityFramework
2+
3+
The PR is adding a new sample that contains the simple Event Sourcing setup with EventStoreDB. For the Read Model, Postgres and Entity Framework are used.
4+
5+
You can watch the webinar on YouTube when I'm explaining the details of the implementation:
6+
7+
<a href="https://www.youtube.com/watch?v=rqYPVzjoxqI" target="_blank"><img src="https://img.youtube.com/vi/rqYPVzjoxqI/0.jpg" alt="Practical introduction to Event Sourcing with EventStoreDB" width="320" height="240" border="10" /></a>
8+
9+
or read the article explaining the read model part: ["How to build event-driven projections with Entity Framework"](https://event-driven.io/en/how_to_do_events_projections_with_entity_framework/)
10+
11+
## Main assumptions:
12+
- explain basics of Event Sourcing, both from the write model (EventStoreDB) and read model part (Postgres and EntityFramework),
13+
- CQRS architecture sliced by business features, keeping code that changes together at the same place. Read more in [How to slice the codebase effectively?](https://event-driven.io/en/how_to_slice_the_codebase_effectively/)
14+
- no aggregates, just data (records) and functions,
15+
- 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.
16+
- easy to use and self-explanatory fluent API for registering commands and projections with possible fallbacks,
17+
- registering everything into regular DI containers to integrate with other application services.
18+
- pushing the type/signature enforcement on edge, so when plugging to DI.
19+
20+
## Overview
21+
22+
It uses:
23+
- pure data entities, functions and handlers,
24+
- Stores events from the command handler result EventStoreDB,
25+
- Builds read models using [Subscription to `$all`](https://developers.eventstore.com/clients/grpc/subscribing-to-streams/#subscribing-to-all).
26+
- Read models are stored to Postgres relational tables with [Entity Framework](https://docs.microsoft.com/en-us/ef/core/).
27+
- App has Swagger and predefined [docker-compose](./docker/docker-compose.yml) to run and play with samples.
28+
29+
## Write Model
30+
- Sample [ShoppingCart](./ECommerce/ShoppingCarts/ShoppingCart.cs#L34) entity and [events](./ECommerce/ShoppingCarts/ShoppingCart.cs#L6) 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](./ECommerce/ShoppingCarts/ShoppingCart.cs#L42) method defining how to apply events to get the entity state. It uses the C#9 switch syntax with records deconstruction.
31+
- Example [ProductItemsList](./ECommerce/ShoppingCarts/ProductItems/ProductItemsList.cs) 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.
32+
- All commands by convention should be created using the [factory method](./ECommerce/ShoppingCarts/AddingProductItem/AddProductItemToShoppingCart.cs#L13) to enforce the types,
33+
- 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](./ECommerce/ShoppingCarts/AddingProductItem/AddProductItemToShoppingCart.cs#L25). This example also shows that you can inject external services to handlers if needed.
34+
- [Added syntax for self-documenting command handlers registration](./ECommerce/ShoppingCarts/Configuration.cs#L22). See the details of registration in [CommandHandlerExtensions](./ECommerce.Core/Commands/CommandHandler.cs). They differentiate case when [a new entity/stream is created](./Ecommerce.Core/Commands/CommandHandler.cs#L11) from the [update case](./Ecommerce.CoreECommerce.Core/Commands/CommandHandler.cs#L25). Update has to support optimistic concurrency.
35+
- Added simple [EventStoreDBRepository](./ECommerce.Core/Entities/EventStoreDBRepository.cs) repository to load entity state and store event created by business logic,
36+
- [New, simplified Core infrastructure](./ECommerce.Core/)
37+
38+
## Read Model
39+
- Read models are rebuilt with eventual consistency using subscribe to $all stream EventStoreDB feature,
40+
- Used Entity Framework to store projection data into Postgres tables,
41+
- Added sample projection for [Shopping cart details](./ECommerce/ShoppingCarts/GettingCartById/ShoppingCartDetails.cs) and slimmed [Shopping cart short info](./ECommerce/ShoppingCarts/GettingCarts/ShoppingCartShortInfo.cs) as an example of different interpretations of the same events. Shopping cart details also contain a nested collection of product items to show more advanced use case. All event handling is done by functions. It enables easier unit and integration testing.
42+
- [Added syntax for self-documenting projection handlers registration](./ECommerce/ShoppingCarts/Configuration.cs#L49). See the details of registration in [EntityFrameworkProjectionBuilder](./ECommerce.Core/Projections/EntityFrameworkProjection.cs#L28). They differentiate case when [a new read model is created](./ECommerce.Core/Projections/EntityFrameworkProjection.cs#L83) from the [update case](./ECommerce.Core/Projections/EntityFrameworkProjection.cs#L108). Update has to support optimistic concurrency.
43+
- [example query handlers](./ECommerce/ShoppingCarts/GettingCarts/GetCarts.cs#25) for reading data together with [registration helpers](./ECommerce.Core/Queries/QueryHandler.cs) for EntityFramework querying.
44+
- Added service [EventStoreDBSubscriptionToAll](./ECommerce.Core/Subscriptions/EventStoreDBSubscriptionToAll.cs) to handle subscribing to all. It handles checkpointing and simple retries when the connection is dropped. Added also general [BackgroundWorker](./ECommerce.Api/Core/BackgroundWorker.cs) to wrap the general `IHostedService` handling
45+
- Added [ISubscriptionCheckpointRepository](./ECommerce.Core/Subscriptions/ISubscriptionCheckpointRepository.cs) for handling Subscription checkpointing.
46+
- Added checkpointing to EventStoreDB stream with [EventStoreDBSubscriptionCheckpointRepository](./ECommerce.Core/Subscriptions/EventStoreDBSubscriptionCheckpointRepository.cs),
47+
- Added custom [EventBus](./ECommerce.Core/Events/EventBus.cs) implementation to not take an additional dependency on external frameworks like MediatR. It's not needed as no advanced pipelining is used here.
48+
49+
## Tests
50+
API integration tests for:
51+
- [Initiating shopping cart](./ECommerce.Api.Tests/ShoppingCarts/Initializing/InitializeShoppingCartTests.cs) as an example of creating a new entity,
52+
- [Confirming shopping cart](./ECommerce.Api.Tests/ShoppingCarts/Confirming/ConfirmShoppingCartTests.cs) as an example of updating an existing entity,
53+
54+
55+
## Prerequisities
56+
57+
1. Install git - https://git-scm.com/downloads.
58+
2. Install .NET Core 5.0 - https://dotnet.microsoft.com/download/dotnet/5.0.
59+
3. Install Visual Studio 2019, Rider or VSCode.
60+
4. Install docker - https://docs.docker.com/docker-for-windows/install/.
61+
5. Open `ECommerce.sln` solution.
62+
63+
## Running
64+
65+
1. Go to [docker](./docker) and run: `docker-compose up`.
66+
2. Wait until all dockers got are downloaded and running.
67+
3. You should automatically get:
68+
- EventStoreDB UI (for event store): http://localhost:2113/
69+
- Postgres DB running (for read models)
70+
- PG Admin - IDE for postgres. Available at: http://localhost:5050.
71+
- Login: `[email protected]`, Password: `admin`
72+
- To connect to server Use host: `postgres`, user: `postgres`, password: `Password12!`
73+
4. Open, build and run `ECommerce.sln` solution.
74+
- Swagger should be available at: http://localhost:5000/index.html

Slides/Event Streaming.pptx

-14.2 MB
Binary file not shown.
-42.3 MB
Binary file not shown.
-38.6 MB
Binary file not shown.
-13 MB
Binary file not shown.
-13.5 MB
Binary file not shown.

Slides/Slides-short.pptx

-3.24 MB
Binary file not shown.

0 commit comments

Comments
 (0)