Skip to content

Commit 057998d

Browse files
committed
Removed Bank Accounts example as it's far from:
- the real-world handling in the banking domain (it's oversimplified), - it's lacking the proper description, so some of the assumptions used (like not using repositories, etc. to show the simplest flow) may be misleading and target to wrong direction, - showing that you can if you want store more than one aggregate is okay if it's explained. Without explanation it may be wrongly interpreted that's the right approach. - there is already other, better ECommerce sample that's showing how to integrate EventSourcing with traditional approach.
1 parent da20909 commit 057998d

File tree

66 files changed

+85
-2075
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+85
-2075
lines changed

EventSourcing.NetCore.sln

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -62,20 +62,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartHome.Api", "Sample\Asy
6262
EndProject
6363
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartHome.Temperature", "Sample\AsyncProjections\SmartHome.Temperature\SmartHome.Temperature.csproj", "{91604B2D-CFDA-4777-BFD1-F459495C96B2}"
6464
EndProject
65-
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BankAccounts", "BankAccounts", "{AE965108-8461-4D7B-A183-41AB4D2BC179}"
66-
EndProject
67-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventSourcing.Sample.Clients", "Sample\BankAccounts\EventSourcing.Sample.Clients\EventSourcing.Sample.Clients.csproj", "{787DB75C-2CE1-4534-8C99-7EC79774F2D3}"
68-
EndProject
69-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventSourcing.Sample.Clients.Contracts", "Sample\BankAccounts\EventSourcing.Sample.Clients.Contracts\EventSourcing.Sample.Clients.Contracts.csproj", "{CFE2108E-7B7F-4264-9378-36A82A99E95D}"
70-
EndProject
71-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventSourcing.Sample.Transactions.Contracts", "Sample\BankAccounts\EventSourcing.Sample.Transactions.Contracts\EventSourcing.Sample.Transactions.Contracts.csproj", "{1683DFB7-2C3E-4416-8B1D-0979F61B22BD}"
72-
EndProject
73-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventSourcing.Sample.Transactions", "Sample\BankAccounts\EventSourcing.Sample.Transactions\EventSourcing.Sample.Transactions.csproj", "{B352BEFA-85D7-4457-9976-1B3063B5B7C1}"
74-
EndProject
75-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventSourcing.Sample.Web", "Sample\BankAccounts\EventSourcing.Sample.Web\EventSourcing.Sample.Web.csproj", "{084FBED7-9B9A-447C-9987-4BB0EAF1E302}"
76-
EndProject
77-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventSourcing.Sample.IntegrationTests", "Sample\BankAccounts\EventSourcing.Sample.IntegrationTests\EventSourcing.Sample.IntegrationTests.csproj", "{344EFF7D-329C-4A1A-B96D-EF6C9A582CF9}"
78-
EndProject
7965
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BuildYourOwnEventStore", "BuildYourOwnEventStore", "{94524EA9-A4BA-4684-99B8-BBE9EE85E791}"
8066
ProjectSection(SolutionItems) = preProject
8167
Workshops\BuildYourOwnEventStore\Readme.md = Workshops\BuildYourOwnEventStore\Readme.md
@@ -256,30 +242,6 @@ Global
256242
{91604B2D-CFDA-4777-BFD1-F459495C96B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
257243
{91604B2D-CFDA-4777-BFD1-F459495C96B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
258244
{91604B2D-CFDA-4777-BFD1-F459495C96B2}.Release|Any CPU.Build.0 = Release|Any CPU
259-
{787DB75C-2CE1-4534-8C99-7EC79774F2D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
260-
{787DB75C-2CE1-4534-8C99-7EC79774F2D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
261-
{787DB75C-2CE1-4534-8C99-7EC79774F2D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
262-
{787DB75C-2CE1-4534-8C99-7EC79774F2D3}.Release|Any CPU.Build.0 = Release|Any CPU
263-
{CFE2108E-7B7F-4264-9378-36A82A99E95D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
264-
{CFE2108E-7B7F-4264-9378-36A82A99E95D}.Debug|Any CPU.Build.0 = Debug|Any CPU
265-
{CFE2108E-7B7F-4264-9378-36A82A99E95D}.Release|Any CPU.ActiveCfg = Release|Any CPU
266-
{CFE2108E-7B7F-4264-9378-36A82A99E95D}.Release|Any CPU.Build.0 = Release|Any CPU
267-
{1683DFB7-2C3E-4416-8B1D-0979F61B22BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
268-
{1683DFB7-2C3E-4416-8B1D-0979F61B22BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
269-
{1683DFB7-2C3E-4416-8B1D-0979F61B22BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
270-
{1683DFB7-2C3E-4416-8B1D-0979F61B22BD}.Release|Any CPU.Build.0 = Release|Any CPU
271-
{B352BEFA-85D7-4457-9976-1B3063B5B7C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
272-
{B352BEFA-85D7-4457-9976-1B3063B5B7C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
273-
{B352BEFA-85D7-4457-9976-1B3063B5B7C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
274-
{B352BEFA-85D7-4457-9976-1B3063B5B7C1}.Release|Any CPU.Build.0 = Release|Any CPU
275-
{084FBED7-9B9A-447C-9987-4BB0EAF1E302}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
276-
{084FBED7-9B9A-447C-9987-4BB0EAF1E302}.Debug|Any CPU.Build.0 = Debug|Any CPU
277-
{084FBED7-9B9A-447C-9987-4BB0EAF1E302}.Release|Any CPU.ActiveCfg = Release|Any CPU
278-
{084FBED7-9B9A-447C-9987-4BB0EAF1E302}.Release|Any CPU.Build.0 = Release|Any CPU
279-
{344EFF7D-329C-4A1A-B96D-EF6C9A582CF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
280-
{344EFF7D-329C-4A1A-B96D-EF6C9A582CF9}.Debug|Any CPU.Build.0 = Debug|Any CPU
281-
{344EFF7D-329C-4A1A-B96D-EF6C9A582CF9}.Release|Any CPU.ActiveCfg = Release|Any CPU
282-
{344EFF7D-329C-4A1A-B96D-EF6C9A582CF9}.Release|Any CPU.Build.0 = Release|Any CPU
283245
{6EF458DC-00FA-45B0-A722-1ACCEB686CAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
284246
{6EF458DC-00FA-45B0-A722-1ACCEB686CAF}.Debug|Any CPU.Build.0 = Debug|Any CPU
285247
{6EF458DC-00FA-45B0-A722-1ACCEB686CAF}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -503,13 +465,6 @@ Global
503465
{8A9E2254-B9BE-4AFC-B6B4-D3733CCF75AE} = {A7186B6B-D56D-4AEF-B6B7-FAA827764C34}
504466
{E4E61DBD-B97C-4A4E-A73F-C37094434983} = {8A9E2254-B9BE-4AFC-B6B4-D3733CCF75AE}
505467
{91604B2D-CFDA-4777-BFD1-F459495C96B2} = {8A9E2254-B9BE-4AFC-B6B4-D3733CCF75AE}
506-
{AE965108-8461-4D7B-A183-41AB4D2BC179} = {A7186B6B-D56D-4AEF-B6B7-FAA827764C34}
507-
{787DB75C-2CE1-4534-8C99-7EC79774F2D3} = {AE965108-8461-4D7B-A183-41AB4D2BC179}
508-
{CFE2108E-7B7F-4264-9378-36A82A99E95D} = {AE965108-8461-4D7B-A183-41AB4D2BC179}
509-
{1683DFB7-2C3E-4416-8B1D-0979F61B22BD} = {AE965108-8461-4D7B-A183-41AB4D2BC179}
510-
{B352BEFA-85D7-4457-9976-1B3063B5B7C1} = {AE965108-8461-4D7B-A183-41AB4D2BC179}
511-
{084FBED7-9B9A-447C-9987-4BB0EAF1E302} = {AE965108-8461-4D7B-A183-41AB4D2BC179}
512-
{344EFF7D-329C-4A1A-B96D-EF6C9A582CF9} = {AE965108-8461-4D7B-A183-41AB4D2BC179}
513468
{94524EA9-A4BA-4684-99B8-BBE9EE85E791} = {CEEE5F74-121E-437F-B3B4-4E7C65482644}
514469
{6EF458DC-00FA-45B0-A722-1ACCEB686CAF} = {0570E45A-2EB6-4C4C-84E4-2C80E1FECEB5}
515470
{A1277765-1C96-4307-A09A-A85E211A59F8} = {0570E45A-2EB6-4C4C-84E4-2C80E1FECEB5}

README.md

Lines changed: 85 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ Tutorial, practical samples and other resources about Event Sourcing in .NET Cor
1414
- [1.6 Retrieving the current state from events](#16-retrieving-the-current-state-from-events)
1515
- [2. Support](#2-support)
1616
- [3. Prerequisites](#3-prerequisites)
17-
- [4. Libraries used](#4-libraries-used)
18-
- [5. Articles](#5-articles)
19-
- [6. Event Store - Marten](#6-event-store---marten)
20-
- [7. Message Bus (for processing Commands, Queries, Events) - MediatR](#7-message-bus-for-processing-commands-queries-events---mediatr)
21-
- [8. CQRS (Command Query Responsibility Separation)](#8-cqrs-command-query-responsibility-separation)
22-
- [9. Fully working sample application](#9-fully-working-sample-application)
23-
- [10. Self-paced training Kit](#10-self-paced-training-kit)
17+
- [4. Tools used](#4-tools-used)
18+
- [5. Fully working sample application](#5-fully-working-sample-application)
19+
- [6. Self-paced training Kit](#6-self-paced-training-kit)
20+
- [7. Articles](#7-articles)
21+
- [8. Event Store - Marten](#8-event-store---marten)
22+
- [9. Message Bus (for processing Commands, Queries, Events) - MediatR](#9-message-bus-for-processing-commands-queries-events---mediatr)
23+
- [10. CQRS (Command Query Responsibility Separation)](#10-cqrs-command-query-responsibility-separation)
2424
- [11. NuGet packages to help you get started.](#11-nuget-packages-to-help-you-get-started)
2525
- [12. Other resources](#12-other-resources)
2626
- [12.1 Introduction](#121-introduction)
@@ -379,13 +379,84 @@ You can also watch my presentation "Practical Event Sourcing with Marten":
379379

380380
<a href="https://www.youtube.com/watch?v=L_ized5xwww&list=PLw-VZz_H4iio9b_NrH25gPKjr2MAS2YgC&index=7" target="_blank"><img src="https://img.youtube.com/vi/L_ized5xwww/0.jpg" alt="Practical Event Sourcing with Marten (EN)" width="320" height="240" border="10" /></a>
381381

382-
## 4. Libraries used
382+
and discussion with [Yves Lorphelin](https://github.com/ylorph/) about CQRS:
383+
384+
<a href="https://www.youtube.com/watch?v=D-3N2vQ7ADE" target="_blank"><img src="https://img.youtube.com/vi/D-3N2vQ7ADE/0.jpg" alt="Event Store Conversations: Yves Lorphelin talks to Oskar Dudycz about CQRS (EN)" width="320" height="240" border="10" /></a>
385+
386+
## 4. Tools used
387+
388+
1. [Marten](https://martendb.io/) - Event Store and Read Models
389+
2. [EventStoreDB](https://eventstore.com) - Event Store
390+
3. [MediatR](https://github.com/jbogard/MediatR) - Internal In-Memory Message Bus (for processing Commands, Queries, Events)
391+
4. [Kafka](https://github.com/jbogard/MediatR) - External Durable Message Bus to integrate services
392+
5. [ElasticSearch](https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/elasticsearch-net-getting-started.html) - Read Models
393+
394+
## 5. Fully working sample application
395+
396+
See also fully working samples of Event Sourcing and CQRS applications in [Samples folder](https://github.com/oskardudycz/EventSourcing.NetCore/tree/main/Sample).
397+
398+
- **[ECommerce with Marten](./Sample/ECommerce)**
399+
- typical Event Sourcing and CQRS flow,
400+
- DDD using Aggregates,
401+
- microservices example,
402+
- stores events to Marten,
403+
- distributed processes coordinated by Saga ([Order Saga](./Sample/ECommerce/Orders/Orders/Orders/OrderSaga.cs)),
404+
- Kafka as a messaging platform to integrate microservices,
405+
- example of the case when some services are event-sourced ([Carts](./Sample/ECommerce/Carts), [Orders](./Sample/ECommerce/Orders), [Payments](./Sample/ECommerce/Payments)) and some are not ([Shipments](./Sample/ECommerce/Shipments) using EntityFramework as ORM)
406+
407+
- **[ECommerce with EventStoreDB](./Sample/EventStoreDB/ECommerce)**
408+
- typical Event Sourcing and CQRS flow,
409+
- DDD using Aggregates,
410+
- stores events to EventStoreDB,
411+
- Builds read models using [Subscription to `$all`](https://developers.eventstore.com/clients/grpc/subscribing-to-streams/#subscribing-to-all).
412+
- Read models are stored as Marten documents.
413+
414+
- **[Warehouse](./Sample/AsyncProjections/)**
415+
- simplest CQRS flow using .NET 5 Endpoints,
416+
- example of how and where to use C# Records, Nullable Reference Types, etc,
417+
- No Event Sourcing! Using Entity Framework to show that CQRS is not bounded to Event Sourcing or any type of storage,
418+
- No Aggregates! CQRS do not need DDD. Business logic can be handled in handlers.
419+
420+
- **[Meetings Management with Marten](./Sample/MeetingsManagement/)**
421+
- typical Event Sourcing and CQRS flow,
422+
- DDD using Aggregates,
423+
- microservices example,
424+
- stores events to Marten,
425+
- Kafka as a messaging platform to integrate microservices,
426+
- read models handled in separate microservice and stored to other database (ElasticSearch)
427+
428+
- **[Cinema Tickets Reservations with Marten](./Sample/Tickets/)**
429+
- typical Event Sourcing and CQRS flow,
430+
- DDD using Aggregates,
431+
- stores events to Marten.
432+
433+
- **[SmartHome IoT with Marten](./Sample/AsyncProjections/)**
434+
- typical Event Sourcing and CQRS flow,
435+
- DDD using Aggregates,
436+
- stores events to Marten,
437+
- asynchronous projections rebuild using AsynDaemon feature.
438+
439+
## 6. Self-paced training Kit
383440

384-
1. [Marten](https://github.com/JasperFx/marten) - Event Store
441+
I prepared the self-paced training Kit for the Event Sourcing. See more in the [Workshop description](./Workshops/BuildYourOwnEventStore/Readme.md).
442+
443+
It's split into two parts:
444+
445+
**Event Sourcing basics** - it teaches the event store basics by showing how to build your Event Store on Relational Database. It starts with the tables setup, goes through appending events, aggregations, projections, snapshots, and finishes with the `Marten` basics. See more in [here](./Workshops/BuildYourOwnEventStore/).
385446

386-
2. [MediatR](https://github.com/jbogard/MediatR) - Message Bus (for processing Commands, Queries, Events)
447+
1. [Streams Table](./Workshops/BuildYourOwnEventStore/01-CreateStreamsTable)
448+
2. [Events Table](./Workshops/BuildYourOwnEventStore/02-CreateEventsTable)
449+
3. [Appending Events](./Workshops/BuildYourOwnEventStore/03-CreateAppendEventFunction)
450+
4. [Optimistic Concurrency Handling](./Workshops/BuildYourOwnEventStore/03-OptimisticConcurrency)
451+
5. [Event Store Methods](./Workshops/BuildYourOwnEventStore/04-EventStoreMethods)
452+
6. [Stream Aggregation](./Workshops/BuildYourOwnEventStore/05-StreamAggregation)
453+
7. [Time Travelling](./Workshops/BuildYourOwnEventStore/06-TimeTraveling)
454+
8. [Aggregate and Repositories](./Workshops/BuildYourOwnEventStore/07-AggregateAndRepository)
455+
9. [Snapshots](./Workshops/BuildYourOwnEventStore/08-Snapshots)
456+
10. [Projections](./Workshops/BuildYourOwnEventStore/09-Projections)
457+
11. [Projections With Marten](./Workshops/BuildYourOwnEventStore/10-ProjectionsWithMarten)
387458

388-
## 5. Articles
459+
## 7. Articles
389460
Read also more on the **Event Sourcing** and **CQRS** topics in my [blog](https://event-driven.io/?utm_source=event_sourcing_net) posts:
390461
- 📝 [What's the difference between a command and an event?](https://event-driven.io/en/whats_the_difference_between_event_and_command/?utm_source=event_sourcing_net)
391462
- 📝 [Events should be as small as possible, right?](https://event-driven.io/en/events_should_be_as_small_as_possible/?utm_source=event_sourcing_net)
@@ -409,7 +480,7 @@ Slides:
409480
- 👨🏼‍🏫 **Ligths and Shades of Event-Driven Design** - [EN](./Slides/Lights_And_Shades_Of_Event-Driven_Design.pptx), [PL](./Slides/SegFault-Blaski_i_Cienie.pptx)
410481
- 👨🏼‍🏫 **Adventures in Event Sourcing and CQRS** - [PL](./Slides/Slides.pptx)
411482

412-
## 6. Event Store - Marten
483+
## 8. Event Store - Marten
413484

414485
- **[Creating event store](https://github.com/oskardudycz/EventSourcing.NetCore/blob/main/Marten.Integration.Tests/General/StoreInitializationTests.cs)**
415486
- **Event Stream** - is a representation of the entity in event sourcing. It's a set of events that happened for the entity with the exact id. Stream id should be unique, can have different types but usually is a Guid.
@@ -467,7 +538,7 @@ Slides:
467538
- **[Projection of single stream](https://github.com/oskardudycz/EventSourcing.NetCore/blob/main/Marten.Integration.Tests/EventStore/Projections/AggregationProjectionsTest.cs)**
468539
- **[Multitenancy per schema](https://github.com/oskardudycz/EventSourcing.NetCore/blob/main/Marten.Integration.Tests/Tenancy/TenancyPerSchema.cs)**
469540
470-
## 7. Message Bus (for processing Commands, Queries, Events) - MediatR
541+
## 9. Message Bus (for processing Commands, Queries, Events) - MediatR
471542

472543
- **[Initialization](https://github.com/oskardudycz/EventSourcing.NetCore/blob/main/MediatR.Tests/Initialization/Initialization.cs)** - MediatR uses services locator pattern to find a proper handler for the message type.
473544
- **Sending Messages** - finds and uses the first registered handler for the message type. It could be used for queries (when we need to return values), commands (when we acting).
@@ -480,42 +551,11 @@ Slides:
480551
- **[More Than One Handler](https://github.com/oskardudycz/EventSourcing.NetCore/blob/main/MediatR.Tests/Publishing/MoreThanOneHandler.cs)** - when there is more than one handler registered MediatR takes all of them when calling Publish method
481552
- Pipeline (to be defined)
482553

483-
## 8. CQRS (Command Query Responsibility Separation)
554+
## 10. CQRS (Command Query Responsibility Separation)
484555

485556
- **[Command handling](https://github.com/oskardudycz/EventSourcing.NetCore/blob/main/CQRS.Tests/Commands/Commands.cs)**
486557
- **[Query handling](https://github.com/oskardudycz/EventSourcing.NetCore/blob/main/CQRS.Tests/Queries/Queries.cs)**
487558
488-
## 9. Fully working sample application
489-
490-
See also fully working sample application in [Sample Project](https://github.com/oskardudycz/EventSourcing.NetCore/tree/main/Sample)
491-
492-
- See [sample](https://github.com/oskardudycz/EventSourcing.NetCore/tree/main/Sample/EventSourcing.Sample.IntegrationTests/Clients/CreateClientTests.cs) how Entity Framework and Marten can coexist together with CQRS and Event Sourcing
493-
494-
## 10. Self-paced training Kit
495-
496-
I prepared the self-paced training Kit for the Event Sourcing. See more in the [Workshop description](./Workshops/BuildYourOwnEventStore/Readme.md).
497-
498-
It's split into two parts:
499-
500-
**Event Sourcing basics** - it teaches the event store basics by showing how to build your Event Store on Relational Database. It starts with the tables setup, goes through appending events, aggregations, projections, snapshots, and finishes with the `Marten` basics. See more in [here](./Workshops/BuildYourOwnEventStore/).
501-
502-
1. [Streams Table](./Workshops/BuildYourOwnEventStore/01-CreateStreamsTable)
503-
2. [Events Table](./Workshops/BuildYourOwnEventStore/02-CreateEventsTable)
504-
3. [Appending Events](./Workshops/BuildYourOwnEventStore/03-CreateAppendEventFunction)
505-
4. [Optimistic Concurrency Handling](./Workshops/BuildYourOwnEventStore/03-OptimisticConcurrency)
506-
5. [Event Store Methods](./Workshops/BuildYourOwnEventStore/04-EventStoreMethods)
507-
6. [Stream Aggregation](./Workshops/BuildYourOwnEventStore/05-StreamAggregation)
508-
7. [Time Travelling](./Workshops/BuildYourOwnEventStore/06-TimeTraveling)
509-
8. [Aggregate and Repositories](./Workshops/BuildYourOwnEventStore/07-AggregateAndRepository)
510-
9. [Snapshots](./Workshops/BuildYourOwnEventStore/08-Snapshots)
511-
10. [Projections](./Workshops/BuildYourOwnEventStore/09-Projections)
512-
11. [Projections With Marten](./Workshops/BuildYourOwnEventStore/10-ProjectionsWithMarten)
513-
514-
**Event Sourcing advanced topics** - it's a real-world sample of the microservices written in Event-Driven design. It explains the topics of modularity, eventual consistency. Shows practical usage of WebApi, Marten as Event Store, Kafka as Event bus and ElasticSearch as one of the read stores. See more in [here](./Workshops/BuildYourOwnEventStore/02-EventSourcingAdvanced/).
515-
516-
1. [Meetings Management Module](./Workshops/Sample/MeetingsManagement) - the module responsible for creating, updating meeting details. Written in `Marten` in **Event Sourcing** pattern. Provides both write model (with Event Sourced aggregates) and read model with projections.
517-
2. [Meetings Search Module](./Workshops/Sample/MeetingsSearch) - responsible for searching and advanced filtering. Uses `ElasticSearch` as storage (because of its advanced searching capabilities). It's a read module that's listening for the events published by the Meetings Management Module.
518-
519559
## 11. NuGet packages to help you get started.
520560

521561
I gathered and generalized all of the practices used in this tutorial/samples in Nuget Packages maintained by me [GoldenEye Framework](https://github.com/oskardudycz/GoldenEye).

0 commit comments

Comments
 (0)