Domain Events 领域事件 完整详解
✅ Domain Events 领域事件 完整详解一、什么是 Domain EventsDomain Event领域事件是领域驱动设计DDD中的一个重要概念当领域中发生一件对业务有意义的事情时所产生的事件。它记录了业务事实而不是技术实现细节。特点过去式命名MainBoardErrorOccurred、ScanCompleted、BatchFinished不可变Immutable包含发生事件所需的最少必要信息由领域实体或领域服务发布二、领域事件 vs 普通事件维度Domain Event领域事件普通 .NET EventC# 事件语义业务意义技术实现命名过去式OrderPlaced任意如ErrorOccurred目的表达业务事实解耦业务流程组件间通知生命周期可持久化、可集成事件总线进程内即时触发处理方式多个处理器Handler异步处理直接订阅架构位置领域层Domain Layer任意层三、领域事件的核心优势高度解耦发布方不需要知道谁会处理事件业务可追溯所有重要业务行为都有记录支持事件溯源Event Sourcing未来可扩展清晰的业务流程通过事件编排复杂的业务流程更好的可测试性支持分布式系统微服务间通过消息队列传递四、在 MaxWell 项目中的实际应用示例1. 定义领域事件推荐放在 Domain 层// MaxWell.Domain/Events/MainBoardErrorOccurred.cspublicrecordMainBoardErrorOccurred{publicstringStationId{get;init;}publicintErrorCode{get;init;}publicstringErrorMessage{get;init;}publicDateTimeOccurredOn{get;init;}DateTime.UtcNow;publicHardwareData?RelatedData{get;init;}}// MaxWell.Domain/Events/ScanCompleted.cspublicrecordScanCompleted{publicstringStationId{get;init;}publicstringHardwareSN{get;init;}publicPlcSignals.ScanResultTypeResult{get;init;}publicDateTimeOccurredOn{get;init;}DateTime.UtcNow;}2. 在领域实体或服务中发布事件// 在 MainBoardService.cs 中protectedoverrideasyncTaskProcessHardwareDataAsync(HardwareDatadata){if(data.AddressErrorCodedata.ValueisinterrorCodeerrorCode!0){vardomainEventnewMainBoardErrorOccurred{StationIdStationId,ErrorCodeerrorCode,ErrorMessageGetErrorMessage(errorCode),RelatedDatadata};await_domainEventPublisher.PublishAsync(domainEvent);// 发布领域事件}if(data.TagScanResultdata.ValueisshortscanValue){varscanEventnewScanCompleted{StationIdStationId,HardwareSNdata.HardwareSN,Result(PlcSignals.ScanResultType)scanValue};await_domainEventPublisher.PublishAsync(scanEvent);}}五、领域事件发布器接口// MaxWell.Domain/Events/IDomainEventPublisher.cspublicinterfaceIDomainEventPublisher{TaskPublishAsyncTEvent(TEventdomainEvent)whereTEvent:class;TaskPublishAsync(IEnumerableobjectdomainEvents);}简单内存实现适合当前阶段publicclassInMemoryDomainEventPublisher:IDomainEventPublisher{privatereadonlyIEnumerableIDomainEventHandler_handlers;publicInMemoryDomainEventPublisher(IEnumerableIDomainEventHandlerhandlers){_handlershandlers;}publicasyncTaskPublishAsyncTEvent(TEventdomainEvent)whereTEvent:class{varhandlers_handlers.OfTypeIDomainEventHandlerTEvent();foreach(varhandlerinhandlers){awaithandler.HandleAsync(domainEvent);}}}六、事件处理器示例// Application/Handlers/MainBoardErrorHandler.cspublicclassMainBoardErrorHandler:IDomainEventHandlerMainBoardErrorOccurred{privatereadonlyIAlarmQueue_alarmQueue;privatereadonlyIStationRepository_repository;publicasyncTaskHandleAsync(MainBoardErrorOccurredevent){// 发送报警_alarmQueue.Enqueue(newAlarmItem(3,$站点[{event.StationId}] 主控板错误:{event.ErrorMessage},event.StationId));// 保存审计日志await_repository.SaveKeyDataAsync(...);}}七、推荐的项目结构调整MaxWell.Domain/ ├── Entities/ ├── Events/ ← 所有领域事件定义 ├── Interfaces/ └── Services/ MaxWell.Application/ └── Handlers/ ← 领域事件处理器总结建议针对您当前阶段立即可落地先使用InMemoryDomainEventPublisher 接口方式后续演进可升级为 MediatR推荐或集成 RabbitMQ / Kafka命名规范全部使用过去式不要滥用只对重要业务事实发布领域事件关注我继续提供以下内容使用MediatR实现领域事件的完整方案强烈推荐MainBoardService完整集成领域事件版本领域事件 Outbox Pattern保证不丢失事件