public async Task <Drawing> PerformDrawingAsync(Drawing drawing) { // todo validate site int siteId = GetCurrentSiteId(); int authUserId = GetClaimId(ClaimType.UserId); if (HasPermission(Permission.PerformDrawing)) { // insert drawing drawing.DrawingCriterion = default(DrawingCriterion); drawing.Id = default(int); drawing = await _drawingRepository.AddSaveAsync(authUserId, drawing); // pull list of eligible users var eligibleUserIds = await _drawingCriterionRepository.GetEligibleUserIdsAsync(drawing.DrawingCriterionId); // ensure there are enough eligible users to do the drawing if (drawing.WinnerCount > eligibleUserIds.Count()) { throw new GraException($"Cannot draw {drawing.WinnerCount} from an eligible pool of {eligibleUserIds.Count()} participants."); } // prepare and perform the drawing var remainingUsers = new List <int>(eligibleUserIds); var rng = System.Security.Cryptography.RandomNumberGenerator.Create(); var randomBytes = new byte[sizeof(int)]; for (int count = 1; count <= drawing.WinnerCount; count++) { rng.GetBytes(randomBytes); int random = System.Math.Abs(System.BitConverter.ToInt32(randomBytes, 0)); int randomUserId = remainingUsers.ElementAt(random % remainingUsers.Count()); var winner = new PrizeWinner { SiteId = siteId, DrawingId = drawing.Id, UserId = randomUserId }; // if there's an associated notification, send it now if (!string.IsNullOrEmpty(drawing.NotificationSubject) && !string.IsNullOrEmpty(drawing.NotificationMessage)) { var mail = new Mail { SiteId = siteId, Subject = drawing.NotificationSubject, Body = drawing.NotificationMessage, ToUserId = winner.UserId, DrawingId = drawing.Id }; mail = await _mailRepository.AddSaveAsync(authUserId, mail); winner.MailId = mail.Id; } // add the winner - does not perform a save await _prizeWinnerRepository.AddAsync(authUserId, winner); // remove them so they aren't drawn twice remainingUsers.Remove(randomUserId); } await _drawingRepository.SaveAsync(); // return the fully-populated drawing return(await _drawingRepository.GetByIdAsync(drawing.Id)); } else { _logger.LogError($"User {authUserId} doesn't have permission to perform drawings."); throw new GraException("Permission denied."); } }