CQRS+MediatR中AddDomainEvent后无法返回值等问题求助
问题1:调用UserManager.UpdateUser后无法返回ResponseLoginViewModel
问题分析
调用_userManager.UpdateUser(应为异步方法UpdateUserAsync)时,会触发DbContext的SaveChangesAsync,而你的SaveChangesAsync先执行DispatchDomainEvents发布领域事件,再执行数据库保存。如果存在以下情况,会导致Handler后续的return res无法正常执行:
- 调用
UpdateUser时未使用await,异步操作后台运行导致主流程异常 DriverLoggedInEventHandler存在异常、无限循环或长时间阻塞操作- 先发布事件再保存的顺序存在数据一致性风险,保存失败时事件已发布
解决方案
保证异步调用等待完成
调用UserManager更新方法时必须使用await,确保操作完成后再执行后续代码:await _userManager.UpdateUserAsync(user);调整领域事件发布时机
将事件发布移到数据库保存之后,避免保存失败却发布事件的脏数据问题:public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default) { try { var result = await base.SaveChangesAsync(cancellationToken); await _mediator.DispatchDomainEvents(this); return result; } catch (Exception e) { Console.WriteLine(e.Message); throw; // 保留原始异常堆栈信息,便于排查 } }排查领域事件处理逻辑
检查DriverLoggedInEventHandler是否存在异常或阻塞操作,确保事件处理能正常完成,不影响主流程执行。
问题2:无法通过Entries<BaseEntity>获取ApplicationUser实体
问题分析
ApplicationUser直接实现了IEntityWithDomainEvent接口,但并未继承BaseEntity抽象类,因此ChangeTracker.Entries<BaseEntity>()只能筛选出继承自BaseEntity的实体,无法识别ApplicationUser。
解决方案
修改DispatchDomainEvents方法,基于IEntityWithDomainEvent接口统一筛选所有包含领域事件的实体,无需单独处理ApplicationUser:
public static class MediatorExtensions { public static async Task DispatchDomainEvents(this IMediator mediator, DbContext context) { // 筛选所有实现IEntityWithDomainEvent接口且包含领域事件的实体 var entities = context.ChangeTracker .Entries() .Select(e => e.Entity as IEntityWithDomainEvent) .Where(e => e != null && e.DomainEvents.Any()) .ToList(); var domainEvents = entities .SelectMany(e => e.DomainEvents) .ToList(); // 清空所有实体的领域事件 entities.ForEach(e => e.ClearDomainEvents()); // 批量发布领域事件 foreach (var domainEvent in domainEvents) await mediator.Publish(domainEvent); } }
这样不管是继承BaseEntity的实体,还是直接实现IEntityWithDomainEvent的ApplicationUser,都会被统一处理,无需单独分支逻辑。
内容的提问来源于stack exchange,提问作者irancss

