public override async Task ExecuteAsync(ReportRequest request, CancellationToken token, IProgress <JobStatus> progress = null) { #region Reporting initialization request = await StartRequestAsync(request); var criterion = await _serviceFacade.ReportCriterionRepository.GetByIdAsync(request.ReportCriteriaId) ?? throw new GraException($"Report criteria {request.ReportCriteriaId} for report request id {request.Id} could not be found."); var report = new StoredReport(); var reportData = new List <object[]>(); int count = 0; #endregion Reporting initialization #region Adjust report criteria as needed IEnumerable <int> badgeIds = null; IEnumerable <int> challengeIds = null; if (!string.IsNullOrEmpty(criterion.BadgeRequiredList)) { try { badgeIds = criterion.BadgeRequiredList.Split(',').Select(int.Parse); } catch (Exception ex) { _logger.LogError($"Unable to convert badge id list to numbers: {ex.Message}"); _logger.LogError($"Badge id list: {criterion.BadgeRequiredList}"); } } if (!string.IsNullOrEmpty(criterion.ChallengeRequiredList)) { try { challengeIds = criterion.ChallengeRequiredList.Split(',').Select(int.Parse); } catch (Exception ex) { _logger.LogError($"Unable to convert challenge id list to numbers: {ex.Message}"); _logger.LogError($"Challenge id list: {criterion.BadgeRequiredList}"); } } int totalCount = challengeIds?.Count() ?? 0; totalCount += badgeIds?.Count() ?? 0; #endregion Adjust report criteria as needed #region Collect data UpdateProgress(progress, 1, "Starting report...", request.Name); // header row report.HeaderRow = new object[] { "Earned Item", "Participants" }; // running totals long totalEarnedItems = 0; if (badgeIds != null) { foreach (var badgeId in badgeIds) { if (token.IsCancellationRequested) { break; } var badgeName = await _badgeRepository.GetBadgeNameAsync(badgeId); var earned = await _userLogRepository.EarnedBadgeCountAsync(criterion, badgeId); UpdateProgress(progress, ++count * 100 / totalCount, $"Processing badge: {badgeName}...", request.Name); reportData.Add(new object[] { badgeName, earned }); totalEarnedItems += earned; } } if (challengeIds != null) { foreach (var challengeId in challengeIds) { if (token.IsCancellationRequested) { break; } var challenge = await _challengeRepository.GetByIdAsync(challengeId); var earned = await _userLogRepository.CompletedChallengeCountAsync(criterion, challengeId); UpdateProgress(progress, ++count * 100 / totalCount, $"Processing challenge: {challenge.Name}...", request.Name); reportData.Add(new object[] { challenge.Name, earned }); totalEarnedItems += earned; } } report.Data = reportData.OrderByDescending(_ => _[1]); report.FooterRow = new object[] { "Total", totalEarnedItems }; report.AsOf = _serviceFacade.DateTimeProvider.Now; #endregion Collect data #region Finish up reporting if (!token.IsCancellationRequested) { ReportSet.Reports.Add(report); } await FinishRequestAsync(request, !token.IsCancellationRequested); #endregion Finish up reporting }