예제 #1
0
        /// <summary>
        /// Executes pipeline behavior:
        ///
        /// Create a new transaction if there is not already an active transaction within the database context,
        /// then await the pipeline result through the <c>RequestHandlerDelegate</c> 'next'.
        /// When the remainder of the pipeline has finished, publish whatever integration events that may have
        /// spawned during the transaction through the event bus.
        /// </summary>
        public async Task <TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate <TResponse> next)
        {
            var response = default(TResponse);

            try
            {
                // Do not start a new transaction if an active one already exists
                if (_context.HasActiveTransaction)
                {
                    _logger.LogDebug("Has active transaction. Calling command handler.");
                    response = await next();

                    _logger.LogDebug("Response: {0}", response);
                    return(response);
                }

                // Execution strategy includes retry on failure
                var strategy = _context.Database.CreateExecutionStrategy();

                await strategy.ExecuteAsync(async() =>
                {
                    Guid transactionId;

                    // Start a new transaction to ensure invariance in the domain
                    using (var transaction = await _context.BeginTransactionAsync())
                    {
                        _logger.LogDebug("New transaction begun. Calling command handler.");
                        response = await next();
                        _logger.LogDebug("Response: {0}", response);

                        // Commit transaction to database, if this fails a rollback of all changes recorded during the transaction will be rolled back
                        await _context.CommitTransactionAsync(transaction);

                        transactionId = transaction.TransactionId;
                    }

                    _logger.LogDebug("TransactionId: {0}", transactionId);
                    // Publish integration events to event bus if everything succeeded
                    await _integrationEventService.PublishEventsThroughEventBusAsync(transactionId);
                });

                return(response);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Something terrible happened in the MediatR Pipeline!");
                throw;
            }
        }