public override async Task Process(Message message)
        {
            BatchUploadValidationProperties properties = message;

            string batchId         = properties.BatchId;
            string fundingStreamId = properties.FundingStreamId;
            string fundingPeriodId = properties.FundingPeriodId;

            BatchUploadBlobName blobName = new BatchUploadBlobName(batchId);

            IBatchUploadReader batchUploadReader = _batchUploadReaderFactory.CreateBatchUploadReader();

            await batchUploadReader.LoadBatchUpload(blobName);

            List <string> publishedProviderIds = new List <string>();
            List <string> missingUkprns        = new List <string>();

            _logger.Information($"Starting validation for batch {batchId} with a total of {batchUploadReader.Count} to check");

            while (batchUploadReader.HasPages)
            {
                string[] page = batchUploadReader.NextPage()?.ToArray() ?? new string[0];

                IDictionary <string, string> publishedProviderIdPage = await _publishedFundingResilience.ExecuteAsync(() => _publishedFunding.GetPublishedProviderIdsForUkprns(fundingStreamId,
                                                                                                                                                                               fundingPeriodId,
                                                                                                                                                                               page)) ?? new Dictionary <string, string>();

                if (page.Length != publishedProviderIdPage.Count)
                {
                    missingUkprns.AddRange(page.Except(publishedProviderIdPage.Keys));
                }

                publishedProviderIds.AddRange(publishedProviderIdPage.Values);

                ItemsProcessed = ItemsProcessed.GetValueOrDefault() + publishedProviderIdPage.Count;
            }

            ItemsProcessed = batchUploadReader.Count;

            if (missingUkprns.Any())
            {
                ItemsFailed = missingUkprns.Count;

                throw new NonRetriableException(
                          $"Did not locate the following ukprns for {fundingStreamId} and {fundingPeriodId}:\n{missingUkprns.JoinWith(',')}");
            }

            byte[] publishedProviderIdsJsonBytes = JsonExtensions.AsJsonBytes(publishedProviderIds.ToArray());

            BatchUploadProviderIdsBlobName batchUploadProviderIdsBlobName = new BatchUploadProviderIdsBlobName(batchId);

            ICloudBlob cloudBlob = _blobClient.GetBlockBlobReference(batchUploadProviderIdsBlobName, ContainerName);

            await _blobClientResilience.ExecuteAsync(() => cloudBlob.UploadFromByteArrayAsync(publishedProviderIdsJsonBytes, 0, publishedProviderIdsJsonBytes.Length));
        }
        public async Task <IActionResult> GetBatchProviderIds(string batchId)
        {
            Guard.IsNullOrWhiteSpace(batchId, nameof(batchId));

            BatchUploadProviderIdsBlobName providerIdsBlobName = new BatchUploadProviderIdsBlobName(batchId);

            await using Stream stream = await BatchStream(providerIdsBlobName);

            if (stream == null)
            {
                _logger.Warning($"Didn't locate the batch provider ids for {batchId}");

                return(new NotFoundResult());
            }

            string[] publishedProviderIds = stream.AsPoco <string[]>();

            return(new OkObjectResult(publishedProviderIds));
        }