原文链接:/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,“Handlemustnotbecalled”);
测试用例1:没有未提交事件的订阅不应调用Handle:
到这里,我将完成我的函数的实现
测试用例2:订阅未提交的事件应该只调用一次Handle:
mockEventSourcingHandler.Verify(m=>m.Handle(It.IsAny<Event>(),It.IsAny<long>()),Times.Once,“Handlemustbecalledonlyonce”).
在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”:”LeLoremIpsumestsimplementdufauxtexte”,“Description”:”LeLoremIpsumestsimplementdufauxtexteemployédanslacompositionetlamiseenpageavantimpression.LeLoremIpsumestlefauxtextestandarddel’imprimeriedepuislesannées1500,quandunimprimeuranonymeassemblaensembledesmorceauxdetextepourréaliserunlivrespécimendepolicesdetexte”,“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测试本地代码
找到\mand\src文件夹(docker-compose.yml文件所在的文件夹)并运行以下命令
docker-composebuilddocker-composeupdockerps–all–format“table{{.ID}}\t{{.Image}}\t{{.Names}}”
启动postman并运行以下 HTTP Post
Endpoint:http://localhost:8080/api/speechMethod:POSTContent-Type:application/jsonBody:{“Title”:”LeLoremIpsumestsimplementdufauxtexte”,“Description”:”LeLoremIpsumestsimplementdufauxtexteemployédanslacompositionetlamiseenpageavantimpression.LeLoremIpsumestlefauxtextestandarddel’imprimeriedepuislesannées1500,quandunimprimeuranonymeassemblaensembledesmorceauxdetextepourréaliserunlivrespécimendepolicesdetexte”,“Url”:”http://www.yahoo_1.fr”,“Type”:”3″}
最后,像这样检查正在运行的容器:
通过运行以下命令打开bash shell(其中0b是logcorner.edusync.speech.presentation.data容器Id的首字母)
Dockerexec-it0b“bash”
连接到sql server linux
/opt/mssql-tools/bin/sqlcmd-Slocalhost-USA-P‘PassW0rd’
运行sql查询
use[LogCorner.EduSync.Speech.Database]goselect*from[dbo].[Speech]goselect*from[dbo].[eventstore]go
应该在Speech表和EventStore表上有记录,版本始终为零,因为本教程不包括更新。
本文的源代码可在此处获得 (Feature/Task/EventSourcingApplication)
/logcorner/LogCorner.mand/tree/Feature/Task/EventSourcingApplication