public async Task <IActionResult> CreateCharacter([FromRoute] string name, [FromServices][NotNull] IPlayfabCharacterClient playfabCharacterClient, [FromServices][NotNull] ICharacterAppearanceRepository characterAppearanceRepository, [FromServices][NotNull] ICharacterDataRepository characterDataRepository) { if (playfabCharacterClient == null) { throw new ArgumentNullException(nameof(playfabCharacterClient)); } if (characterAppearanceRepository == null) { throw new ArgumentNullException(nameof(characterAppearanceRepository)); } if (characterDataRepository == null) { throw new ArgumentNullException(nameof(characterDataRepository)); } if (string.IsNullOrWhiteSpace(name)) { throw new ArgumentException("Value cannot be null or whitespace.", nameof(name)); } int accountId = ClaimsReader.GetAccountIdInt(User); bool nameIsAvailable = await ValidateNameAvailability(name); if (!nameIsAvailable) { return(BadRequest(new CharacterCreationResponse(CharacterCreationResponseCode.NameUnavailableError))); } string playfabId = ClaimsReader.GetPlayfabId(User); //Now, we actually need to create the character on PlayFab first. It's better to have an orphaned character on PlayFab //than to have a character without a PlayFab equivalent. PlayFabResultModel <GladMMOPlayFabGrantCharacterToUserResult> playFabResultModel = await playfabCharacterClient.GrantCharacterToUser(new GladMMOPlayFabGrantCharacterToUserRequest(name, "test", playfabId)); //TODO: Better error handling if (playFabResultModel.ResultCode != HttpStatusCode.OK) { if (Logger.IsEnabled(LogLevel.Error)) { Logger.LogError($"PlayFab CharacterCreation Erorr: {playFabResultModel.ResultCode}:{playFabResultModel.ResultStatus}"); } return(BadRequest(new CharacterCreationResponse(CharacterCreationResponseCode.GeneralServerError))); } CharacterEntryModel characterEntryModel = new CharacterEntryModel(accountId, name, playfabId, playFabResultModel.Data.CharacterId); //TODO: We need a transition around the creation of the below entries. ProjectVersionStage.AssertBeta(); //TODO: Don't expose the database table model //Otherwise we should try to create. There is a race condition here that can cause it to still fail //since others could create a character with this name before we finish after checking bool result = await CharacterRepository.TryCreateAsync(characterEntryModel); //TODO: Also needs to be apart of the transaction if (result) { await characterDataRepository.TryCreateAsync(new CharacterDataModel(characterEntryModel.CharacterId, 0)); await characterAppearanceRepository.TryCreateAsync(new CharacterAppearanceModel(characterEntryModel.CharacterId, 9)); //Default is 9 right now. } return(Json(new CharacterCreationResponse(CharacterCreationResponseCode.Success))); }