eShop
eShop copied to clipboard
Explanation for when to handle domain events may be incorrect?
In the OrderingContext class there is the following method:
public async Task<bool> SaveEntitiesAsync(CancellationToken cancellationToken = default)
{
// Dispatch Domain Events collection.
// Choices:
// A) Right BEFORE committing data (EF SaveChanges) into the DB will make a single transaction including
// side effects from the domain event handlers which are using the same DbContext with "InstancePerLifetimeScope" or "scoped" lifetime
// B) Right AFTER committing data (EF SaveChanges) into the DB will make multiple transactions.
// You will need to handle eventual consistency and compensatory actions in case of failures in any of the Handlers.
await _mediator.DispatchDomainEventsAsync(this);
// After executing this line all the changes (from the Command Handler and Domain Event Handlers)
// performed through the DbContext will be committed
_ = await base.SaveChangesAsync(cancellationToken);
return true;
}
I'm wondering if the explanation in the comments of this method is correct, given that the commands are handled through a PipelineBehavior TransactionBehavior, which has the following Handle method:
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
{
...
try
{
...
await strategy.ExecuteAsync(async () =>
{
Guid transactionId;
await using var transaction = await _dbContext.BeginTransactionAsync();
using (_logger.BeginScope(new List<KeyValuePair<string, object>> { new("TransactionContext", transaction.TransactionId) }))
{
...
response = await next();
...
await _dbContext.CommitTransactionAsync(transaction);
transactionId = transaction.TransactionId;
}
await _orderingIntegrationEventService.PublishEventsThroughEventBusAsync(transactionId);
});
return response;
}
catch (Exception ex)
{
...
throw;
}
}
And, as explained in the EF Core docs, using the BeginTransactionAsync method makes that any subsequent call to SaveChangesAsync becomes part of the same transaction.
So, in this situation, it wouldn't matter whether await _mediator.DispatchDomainEventsAsync(this); was called before or after await base.SaveChangesAsync(cancellationToken);, right? Or what am I misunderstanding / missing?