[ValidateNewPlayer] // Perform new Player validations (Validators\ValidateNewPlayer.cs)
        public async Task <IActionResult> Add([FromBody] PlayerAddRequest model)
        {
            // at this point model has been validated
            var newPlayer = _mapper.Map <Player>(model);

            newPlayer.Active = true; // set initial status of player to Active

            // ReSharper disable once MethodHasAsyncOverload
            // AddAsync() overload has special use-case for client-side HiLo generated PKs
            _db.Players.Add(newPlayer);

            // Save Unit-of-Work
            // do not handle exceptions here to let other
            // services know we failed and they need to retry
            await _db.SaveChangesAsync();

            // TODO: More structured logging with NLog
            _logger.LogInformation($@">>> PlayerController.Add() success - Id ""{model.TransactionId}"", Name ""{model.PlayerName}"".");

            var result = _mapper.Map <Player, PlayerModelResponse>(newPlayer);

            return(Created($"/v1/{ControllerContext.ActionDescriptor.ControllerName}/{model.TransactionId}", result));
        }
Exemple #2
0
        public async Task <IActionResult> AttemptTransaction([FromRoute] Guid walletGuid, [FromBody] WalletOperationRequest model)
        {
            // At this point Model is validated
            // Get player's Wallet tracked Entity
            var playersWallet = await _db.Wallet
                                .Where(wallet => wallet.Id == walletGuid)
                                .FirstOrDefaultAsync();

            // If we're dealing with negative transaction type
            if (NegativeTransactionTypes.Contains(model.TransactionType))
            {
                // check if it results in positive Balance in the end
                if ((playersWallet.Balance - model.Amount) < decimal.Zero)
                {
                    _logger.LogWarning($@">>> WalletController.AttemptTransaction() - Operation of {nameof(model.TransactionType)} with Amount of {model.Amount} would result in negative balance!.");
                    return(new UnprocessableEntityObjectResult(UnprocessableWalletLogResponseObject));
                }

                // Update Player's Wallet Balance
                playersWallet.Balance -= model.Amount;
            }

            if (PositiveTranscationTypes.Contains(model.TransactionType))
            {
                // Update Player's Wallet Balance
                playersWallet.Balance += model.Amount;
            }

            // perform the operation and log to operations log
            // runs in an implicit transaction

            // prepare OkResult
            var result = new WalletOperationResult
            {
                Id          = model.TransactionId,
                Repeated    = false,
                Success     = true,
                WalletState = new WalletModelResponse
                {
                    Balance = playersWallet.Balance
                }
            };

            // ReSharper disable once MethodHasAsyncOverload
            // Async overload serves only purpose for special HiLo generated PKs
            _db.WalletLogs.Add(
                new WalletLog
            {
                CreatedAt     = DateTime.Now,
                ResultType    = ResultType.Created,
                WalletId      = walletGuid,
                TransactionId = model.TransactionId,
                Memento       = JsonSerializer.Serialize(result, _databaseSerializerOptions)
            }
                );

            try
            {
                await _db.SaveChangesAsync();
            }
            catch (DBConcurrencyException)
            {
                // Optimistic concurrency failed as the object
                // has been changed during this transaction.
                // Signal this back to the client which is
                // responsible for retry!
                _logger.LogDebug($@">>> WalletController.AttemptTransaction() - This transaction failed optimistic concurrency!");
                return(new CustomPreconditionFailedResult());
            }

            // TODO: Fill in uri to Get method where the transaction can be found
            return(Created("", result));
        }