Building microservices through Event Driven Architecture part8: Implementing EventSourcing on Application
This tutorial is the 8th part of a series : Building microservices through Event Driven Architecture.
The previous step is about Building microservices through Event Driven Architecture part7: Implementing EventSourcing on Repositories : https://logcorner.com/building-microservices-through-event-driven-architecture-part7-implementing-eventsourcing-on-repositories/
During this journey, I will talk about Event Sourcing implementation on Application.
This layer surrounds the domain and implements the uses cases (the application specific business rules).
It orchestrate the data flow and use the domain model and infrastructures, and have no dependency to a database, UI or special frameworks.
For the purposes of our eventsourcing system , I will take all the uncommited events from the aggregate and call a function of the repository which will have the responsibility to save the events in the eventstore. So I will call the function AppendAsync(EventStore @event) of IEventStoreRepository.
Because I have not yet implemented the updates, I will not take care about the aggregate version, (I have a single post method that creates a speech, so the aggregate version will always be equal to zero).
When I will implement the updates, I will take care about the aggregate version in the application and presentation layers.
EVENT SOURCING INTERFACES
I can define two interfaces IEventSourcingSubscriber and IEventSourcingHandler, you can use another naming convention, but for now I leave them as they are.
- Subscribe is a function that get all uncommited events from the aggregate and for each event call a function Handle that take a event and the current aggregate version as inputs.
- Handle is a function that serialize the event into a string and call AppendAsync(EventStore @event) of IEventStoreRepository .
EVENT SOURCING IMPLEMENTATION
EVENTSOURCING SUBSCRIBER IMPLEMENTATION
So the first test sould be : Subscribe with no uncommitted events should not call handle
I have no uncommitted events , I will do nothing. Then the Assert section will look like this :
mockEventSourcingHandler.Verify(m => m.Handle(It.IsAny<Event>(),It.IsAny<long>()), Times.Never, “Handle must not be called”);
TEST CASE 1 : Subscribe with no uncommitted events should not call handle:
Here, I will finish the implementation of my function
TEST CASE 2 : Subscribe with uncommitted events should call handle only once:
mockEventSourcingHandler.Verify(m => m.Handle(It.IsAny<Event>(),It.IsAny<long>()), Times.Once, “Handle must be called only once”).
In the Assert section, I can verify that the Handle function is called only once.
And the final implementation of EventSourcingSubscriber should look like this :
I call handle function for each event.
EVENTSOURCING HANDLER IMPLEMENTATION
TEST CASE 3 : Handle with null events should raise EventNullException:
I mock some dependencies and verify that if the event is null, then handle should raise an exception.
Here is the implementation of the test.
TEST CASE 4 : Handle with events should call AppendAsync :
Here I verify that if the event is not null, then Handle should call AppendAsync
Here is the implementation of the test. You can observe that I use a IEventSerializer interface to serialize the event into a json string, this json string will be the payload of the event stream.
UPDATE REGISTERSPEECHUSECASE
Then upade the RegisterSpeechUseCase and call Subscribe function : await _domainEventSubscriber.Subscribe(speech);
UPDATE PRESENTATION
Open Startup.cs file and configure some dependency injections
Open appsettings.Development.json and upade the ConnectionStrings to use the appropriate database server, database name and credentials.
Scripts to create dabase are located in LogCorner.EduSync.Speech.Database project
TEST USING POSTAMAN
TEST LOCAL CODE USING VISUAL STUDIO
Select LogCorner.EduSync.Speech.Presentation projet and hit F5
Launch postman and run the following HTTP Post
Endpoint : http://localhost:62694/api/speech
Method : POST
Content-Type: application/json
Body : {
“Title”:”Le Lorem Ipsum est simplement du faux texte”,
“Description”:”Le Lorem Ipsum est simplement du faux texte employé dans la composition et la mise en page avant impression. Le Lorem Ipsum est le faux texte standard de l’imprimerie depuis les années 1500, quand un imprimeur anonyme assembla ensemble des morceaux de texte pour réaliser un livre spécimen de polices de texte”,
“Url”:”http://www.yahoo_1.fr”,
“Type”:”3″
}
Open Sql server Management studio and run the following commands :
SELECT * FROM [LogCorner.EduSync.Speech.Data].[dbo].[Speech]
SELECT * FROM [LogCorner.EduSync.Speech.Data].[dbo].[EventStore]
The result should look like this :
As a result, I should have records on Speech table and on EventStore table, the version is always equal to zero because this tutorial does not cover updates.
TEST LOCAL CODE USING DOCKER
locate \LogCorner.EduSync.Command\src folder (the folder where is located docker-compose.yml file) and run the following command
- docker-compose build
- docker-compose up
- docker ps –all –format “table {{.ID}}\t{{.Image}}\t{{.Names}}”
Launch postman and run the following HTTP Post
Endpoint : http://localhost:8080/api/speech
Method : POST
Content-Type: application/json
Body : {
“Title”:”Le Lorem Ipsum est simplement du faux texte”,
“Description”:”Le Lorem Ipsum est simplement du faux texte employé dans la composition et la mise en page avant impression. Le Lorem Ipsum est le faux texte standard de l’imprimerie depuis les années 1500, quand un imprimeur anonyme assembla ensemble des morceaux de texte pour réaliser un livre spécimen de polices de texte”,
“Url”:”http://www.yahoo_1.fr”,
“Type”:”3″
}
Finally , inspect the running containers like this :
Open a bash shell by running the following command ( where 0b is first letters of logcorner.edusync.speech.presentation.data container Id)
- Docker exec -it 0b “bash”
Connect to sql server linux
- /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P ‘PassW0rd’
Run sql queries
use [LogCorner.EduSync.Speech.Database]
go
select * from [dbo].[Speech]
go
select * from [dbo].[eventstore]
go
As a result, I should have records on Speech table and on EventStore table, the version is always equal to zero because this tutorial does not cover updates.
Cource code of this article is available here (Feature/Task/EventSourcingApplication)
Regards