Задать вопрос

Domain events, как решить проблему?

Использую MediatR, .net 7, EF.
Есть пользователь, у которого на данный момент есть 2 события: AccountPasswordChangedEvent, TokensWasRemovedEvent.
AccountPasswordChangedEvent вызывается в UpdateUserPasswordCommandHandler:

private readonly IAccountService accountService;
private readonly IDomainEventsService eventsService;

public UpdateUserPasswordCommandHandler(IAccountService accountService, IDomainEventsService eventsService)
{
    this.accountService = accountService;
    this.eventsService = eventsService;
}

public async Task<ServiceResult<ResetPasswordResponse>> Handle(UpdateUserPasswordCommand request, CancellationToken cancellationToken)
{
    var (userId, res) = await accountService.ResetPasswordAsync(request, false, cancellationToken);
    if (res.Succeeded)
    {
        await eventsService.PublishAsync(new AccountPasswordChanged(userId));
    }
    return new ServiceResult<ResetPasswordResponse>(res);
}

В свою очередь обработчик AccountPasswordChangedEvent удаляет все токены пользователя:

private readonly IAccountService accountService;

public AccountPasswordChangedHandler(IAccountService accountService)
{
    this.accountService = accountService;
}

public Task Handle(DomainEventNotification<AccountPasswordChangedEvent> notification, CancellationToken cancellationToken)
{
    return accountService.RemoveTokenAsync(new LogoutCommand
    {
        UserId = notification.DomainEvent.UserId,
        RemoveType = RemoveTokenType.All
    }, cancellationToken);
}

TokensWasRemovedEvent вызывается в LogoutCommandHandler:

private readonly IAccountService accountService;
private readonly IDomainEventsService publisher;

public LogoutCommandHandler(IAccountService accountService, IDomainEventsService publisher)
{
    this.accountService = accountService;
    this.publisher = publisher;
}

public async Task<ServiceResult<LogoutResponse>> Handle(LogoutCommand request, CancellationToken cancellationToken)
{
    var result = await accountService.RemoveTokenAsync(request, cancellationToken);
    if (result.Length > 0)
    {
        await publisher.PublishAsync(new TokensWasRemovedEvent(result));
    }
    return new ServiceResult<LogoutResponse>(new LogoutResponse { Count = result.Length });
}

Где обработчик этого события удаляет все удаленные токены из кеша:

private readonly IMemoryCache memoryCache;

public TokenWasRemovedHandler(IMemoryCache memoryCache)
{
    this.memoryCache = memoryCache;
}

public Task Handle(DomainEventNotification<TokensWasRemovedEvent> notification, CancellationToken cancellationToken)
{
    foreach (var item in notification.DomainEvent.Tokens)
    {
        memoryCache.Remove($"apitoken={item}");
    }
    return Task.CompletedTask;
}

Вопрос такой: можно ли пробросить новое событие TokensWasRemovedEvent в обработчике события AccountPasswordChangedHandler? Правильно ли это будет (могут ли события порождать события? Я такого не видел нигде, а если быть точнее, то видел и там было сказано, что это плохо)?

private readonly IAccountService accountService;
private readonly IDomainEventsService publisher;

public AccountPasswordChangedHandler(IAccountService accountService, IDomainEventsService publisher)
{
    this.accountService = accountService;
    this.publisher = publisher;
}

public async Task Handle(DomainEventNotification<AccountPasswordChangedEvent> notification, CancellationToken cancellationToken)
{
    var tokens = await accountService.RemoveTokenAsync(new LogoutCommand
    {
        UserId = notification.DomainEvent.UserId,
        RemoveType = RemoveTokenType.All
    }, cancellationToken);
    if (tokens.Length > 0)
    {
        await publisher.PublishAsync(new TokensWasRemovedEvent(tokens));
    }
}

Сразу отвечаю на вопрос "Почему события добавляются не через DbContext & Entity?" - удаление токенов происходит через ExecuteDeleteAsync (.net 7), который не затрагивает SaveChangesAsync. Смена пароля происходит через UserManager из которого нужно сначала получить ответ, что пароль изменен успешно (может вернуть IdentityError[]).
  • Вопрос задан
  • 203 просмотра
Подписаться 4 Простой 1 комментарий
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы