public async Task <TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate <TResponse> next) { TResponse response = default(TResponse); try { var strategy = _dbContext.Database.CreateExecutionStrategy(); await strategy.ExecuteAsync(async() => { _logger.LogInformation($"Begin transaction {typeof(TRequest).Name}"); await _dbContext.BeginTransactionAsync(); response = await next(); await _dbContext.CommitTransactionAsync(); _logger.LogInformation($"Committed transaction {typeof(TRequest).Name}"); await _orderingIntegrationEventService.PublishEventsThroughEventBusAsync(); }); return(response); } catch (Exception) { _logger.LogInformation($"Rollback transaction executed {typeof(TRequest).Name}"); _dbContext.RollbackTransaction(); throw; } }
// Network resilience / managing optimistic concurrency // Handling many database operations (save changes) in an atomic manner // Publishes integration events public async Task <TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate <TResponse> next) { var response = default(TResponse); var typeName = request.GetGenericTypeName(); try { var strategy = _orderingContext.Database.CreateExecutionStrategy(); await strategy.ExecuteAsync(async() => { Guid transactionId; using (var transaction = await _orderingContext.Database.BeginTransactionAsync(cancellationToken)) { _logger.LogInformation("----- Begin transaction {TransactionId} for {RequestName} ({@Request})", transaction.TransactionId, typeName, request); response = await next(); _logger.LogInformation("----- Commit transaction {TransactionId} for {RequestName}", transaction.TransactionId, typeName); try { await _orderingContext.SaveChangesAsync(cancellationToken); transaction.Commit(); } catch (Exception) { transaction.Rollback(); throw; } transactionId = transaction.TransactionId; } await _orderingIntegrationEventService.PublishEventsThroughEventBusAsync(transactionId); }); return(response); } catch (Exception ex) { _logger.LogError(ex, "ERROR Handling transaction for {RequestName} ({@Request})", typeName, request); throw; } }
/// <summary> /// The behavior handler implementation /// </summary> /// <param name="request"></param> /// <param name="cancellationToken"></param> /// <param name="next"></param> /// <returns></returns> public async Task <TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate <TResponse> next) { var response = default(TResponse); var typeName = request.GetGenericTypeName(); try { if (_dbContext.HasActiveTransaction) { return(await next()); } var strategy = _dbContext.Database.CreateExecutionStrategy(); await strategy.ExecuteAsync(async() => { Guid transactionId; using (var transaction = await _dbContext.BeginTransactionAsync()) using (LogContext.PushProperty("TransactionContext", transaction.TransactionId)) { _logger.LogInformation("----- Begin transaction {TransactionId} for {CommandName} ({@Command})", transaction.TransactionId, typeName, request); response = await next(); _logger.LogInformation("----- Commit transaction {TransactionId} for {CommandName}", transaction.TransactionId, typeName); await _dbContext.CommitTransactionAsync(transaction); transactionId = transaction.TransactionId; } // Publish the integration event await _orderingIntegrationEventService.PublishEventsThroughEventBusAsync(transactionId); }); return(response); } catch (Exception ex) { _logger.LogError(ex, "ERROR Handling transaction for {CommandName} ({@Command})", typeName, request); throw; } }