原文链接:https://logcorner.com/building-microservices-through-event-driven-architecture-part8-implementing-eventsourcing-on-application/
在本文中,我将讨论应用程序上的事件溯源实现。
该层围绕领域并实现用例(特定于应用程序的业务规则)。
它编排数据流并使用领域模型和基础架构,并且不依赖于数据库、UI或特殊框架。
出于我们的事件溯源系统的目的,我将从聚合中取出所有未提交的事件并调用仓储的函数,该函数负责将事件保存在事件存储中。所以我会调用IEventStoreRepository 的AppendAsync(EventStore @event)函数。
因为我还没有实现更新,所以我不会关心聚合版本,(我有一个创建语音的post方法,所以聚合版本将始终等于0)。当我实现更新时,我会关注应用层和表现层中的聚合版本。
事件溯源接口
我可以定义两个接口IEventSourcingSubscriber和IEventSourcingHandler,您可以使用另一种命名约定,但现在我保留它们原样。
Subscribe 一个函数,它从聚合中获取所有未提交的事件,并为每个事件调用一个函数Handle,该函数将事件和当前聚合版本作为输入。
Handle是将事件序列化为字符串并调用IEventStoreRepository的AppendAsync(EventStore @event)的函数。
事件溯源实现
事件资源订阅者实现
所以第一个测试应该是:没有未提交事件的订阅不应该调用Handle
我没有未完成的事件,我什么也不做。然后断言部分将如下所示:
mockEventSourcingHandler.Verify(m => m.Handle(It.IsAny<Event>(),It.IsAny<long>()), Times.Never, “Handle must not be called”);
测试用例1:没有未提交事件的订阅不应调用Handle:
到这里,我将完成我的函数的实现
测试用例2:订阅未提交的事件应该只调用一次Handle:
mockEventSourcingHandler.Verify(m => m.Handle(It.IsAny<Event>(),It.IsAny<long>()), Times.Once, “Handle must be called only once”).
在Assert部分,我可以验证Handle函数仅被调用一次。
EventSourcingSubscriber的最终实现应该是这样的:
我为每个事件调用Handle函数。
事件源处理程序实现
测试用例3:处理空事件应该引发EventNullException:
我模拟了一些依赖项并验证如果事件为空,那么Handle应该引发异常。
下面是测试的实现。
测试用例34:处理事件应调用AppendAsync:
这里我验证如果事件不为空,那么Handle应该调用AppendAsync
下面是测试的实现。您可以观察到我使用 IEventSerializer 接口将事件序列化为 json 字符串,此 json 字符串将作为事件流的有效负载。
更新REGISTERSPEECHUSECASE
然后更新RegisterSpeechUseCase并调用Subscribe函数:await _domainEventSubscriber.Subscribe(speech);
更新PRESENTATION
打开Startup.cs文件并配置一些依赖注入
打开appsettings.Development.json并更新ConnectionStrings以使用适当的数据库服务器、数据库名称和凭据。
创建数据库的脚本位于LogCorner.EduSync.Speech.Database项目中
使用POSTAMAN测试
使用VISUAL STUDIO测试本地代码
选择LogCorner.EduSync.Speech.Presentation项目并点击F5
启动postman并运行以下HTTP Post
Endpoint : http://localhost:62694/api/speechMethod : POSTContent-Type: application/jsonBody : {
“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″
}
打开Sql Server Management Studio并运行以下命令:
SELECT * FROM [LogCorner.EduSync.Speech.Data].[dbo].[Speech] SELECT * FROM [LogCorner.EduSync.Speech.Data].[dbo].[EventStore]
结果应该是这样的:
应该在Speech表和EventStore表上有记录,版本始终为零,因为本教程不包括更新。
使用Docker测试本地代码
找到\LogCorner.EduSync.Command\src文件夹(docker-compose.yml文件所在的文件夹)并运行以下命令
docker-compose build
docker-compose up
docker ps –all –format “table {{.ID}}\t{{.Image}}\t{{.Names}}”
启动postman并运行以下 HTTP Post
Endpoint : http://localhost:8080/api/speechMethod : POSTContent-Type: application/jsonBody : {
“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″
}
最后,像这样检查正在运行的容器:
通过运行以下命令打开bash shell(其中0b是logcorner.edusync.speech.presentation.data容器Id的首字母)
Docker exec -it 0b “bash”
连接到sql server linux
/opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P ‘PassW0rd’
运行sql查询
use [LogCorner.EduSync.Speech.Database]
goselect * from [dbo].[Speech]
goselect * from [dbo].[eventstore]
go
应该在Speech表和EventStore表上有记录,版本始终为零,因为本教程不包括更新。
本文的源代码可在此处获得 (Feature/Task/EventSourcingApplication)
https://github.com/logcorner/LogCorner.EduSync.Speech.Command/tree/Feature/Task/EventSourcingApplication