[英]Why Not returning value after AddDomainEvent in CQRS pattern
我在我的项目中使用 CQRS 模式和 MediatR。在 2 个部分中,它并没有像我期望的那样结束。
1:当我想用命令改变后返回一个值时,我使用(例如:usermanager)保存更改,所以创建的视图model不再返回,而是发送到事件推送路径。
基础实体:
public abstract class BaseEntity : IBaseId<string>, IEntityWithDomainEvent
{
public string Id { get; set; }
private readonly List<BaseEvent> _domainEvents = new();
[NotMapped]
public IReadOnlyCollection<BaseEvent> DomainEvents => _domainEvents.AsReadOnly();
public void AddDomainEvent(BaseEvent domainEvent)
{
_domainEvents.Add(domainEvent);
}
public void RemoveDomainEvent(BaseEvent domainEvent)
{
_domainEvents.Remove(domainEvent);
}
public void ClearDomainEvents()
{
_domainEvents.Clear();
}
}
public class LoginUserCommand : IRequest<ResponseLoginViewModel>
{
public string PhoneNumber { get; set; }
public string VerifyCode { get; set; }
public string ReturnUrl { get; set; }
}
public class LoginUserCommandHandler : IRequestHandler<LoginUserCommand, ResponseLoginViewModel>
{
private readonly IIdentityService _identityService;
public LoginUserCommandHandler(IIdentityService identityService)
{
_identityService = identityService;
}
public async Task<ResponseLoginViewModel> Handle(LoginUserCommand request, CancellationToken cancellationToken)
{
var user = await _identityService.GetUserWithMobileAsync(request.PhoneNumber);
if (user.VerifyCode == request.VerifyCode)
{
var res = await _identityService.LoginUser(user);
user.RefreshToken = res.RefreshToken;
user.RefreshTokenExpiryTime = res.Expiration;
user.AddDomainEvent(new DriverLoggedInEvent(user));
user.VerifyCode = await _identityService.GenerateRandomCode();
//TODO: Here If I use _usermanager.updateuser it no longer returns to (return res) and
goes to the DriverLoggedInEventHandler class
if (string.IsNullOrEmpty(res.Token))
{
return new ResponseLoginViewModel();
}
return res;
}
return new ResponseLoginViewModel();
}
}
2:我的 ApplicationUser class 继承自 IdentityUser 和我创建的接口:IEntityWithDomainEvent。
public interface IEntityWithDomainEvent
{
IReadOnlyCollection<BaseEvent> DomainEvents { get; }
void AddDomainEvent(BaseEvent domainEvent);
void RemoveDomainEvent(BaseEvent domainEvent);
void ClearDomainEvents();
}
但是我不能在savechange的时候put.Entries(),所以我现在用最愚蠢的方式传递了它。
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
try
{
await _mediator.DispatchDomainEvents(this);
return await base.SaveChangesAsync(cancellationToken);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
throw new Exception(e.Message);
}
}
调度域事件:
public static class MediatorExtensions
{
public static async Task DispatchDomainEvents(this IMediator mediator, DbContext context)
{
var entities = context.ChangeTracker
.Entries<BaseEntity>()
.Where(e => e.Entity.DomainEvents.Any())
.Select(e => e.Entity);
var domainEvents = entities
.SelectMany(e => e.DomainEvents)
.ToList();
entities.ToList().ForEach(e => e.ClearDomainEvents());
// TODO : Problem two is solved for now by the following silly method
if (domainEvents.Count == 0)
{
var entities2 = context.ChangeTracker
.Entries<ApplicationUser>()
.Where(e => e.Entity.DomainEvents.Any())
.Select(e => e.Entity);
domainEvents = entities2
.SelectMany(e => e.DomainEvents)
.ToList();
entities2.ToList().ForEach(e => e.ClearDomainEvents());
}
foreach (var domainEvent in domainEvents)
await mediator.Publish(domainEvent);
}
}
预先感谢您的帮助
Update1:在 LoginUserCommandHandler 中:请阅读 TODO 部分。 问题出在 TODO 部分的 DispatchDomainEvent 部分。 LoginUserCommandHandler中用_usermanager.updateuser更新用户后,因为数据库保存了,所以LoginUserCommandHandler中return res的值没有返回
不确定实际问题是什么,但至于DispatchDomainEvents
似乎BaseEntity
应该实现IEntityWithDomainEvent
如果它实现了 - 你可以使用简化实现的接口:
public static async Task DispatchDomainEvents(this IMediator mediator, DbContext context)
{
var entities = context.ChangeTracker
.Entries<IEntityWithDomainEvent>()
.Where(e => e.Entity.DomainEvents.Any())
.Select(e => e.Entity);
var domainEvents = entities
.SelectMany(e => e.DomainEvents)
.ToList();
entities.ToList().ForEach(e => e.ClearDomainEvents());
foreach (var domainEvent in domainEvents)
await mediator.Publish(domainEvent);
}
entities
的双重枚举也可能不理想,因此:
public static async Task DispatchDomainEvents(this IMediator mediator, DbContext context)
{
var entities = context.ChangeTracker
.Entries<IEntityWithDomainEvent>()
.Where(e => e.Entity.DomainEvents.Any())
.Select(e => e.Entity);
foreach (var entity in entities)
{
foreach (var domainEvent in entity.DomainEvents)
{
await mediator.Publish(domainEvent);
}
entity.ClearDomainEvents();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.