public async Task <PublishSourcePointResult> PublishSourcePointList(IEnumerable <PublishSourcePointForm> publishSourcePointForms) { try { var sourcePointIdList = publishSourcePointForms.Select(o => o.SourcePointId).ToArray(); var sourcePointList = _dbContext.SourcePoints.Include(o => o.Catalog).Where(o => sourcePointIdList.Contains(o.Id)).ToList(); var currentUser = _userProfileService.GetCurrentUser(); //Update database IList <PublishedHistory> histories = new List <PublishedHistory>(); foreach (var sourcePoint in sourcePointList) { var sourcePointForm = publishSourcePointForms.First(o => o.SourcePointId == sourcePoint.Id); sourcePoint.Value = sourcePointForm.CurrentValue; sourcePoint.Position = sourcePointForm.Position; sourcePoint.Name = sourcePointForm.Name; sourcePoint.NamePosition = sourcePointForm.NamePosition; var history = new PublishedHistory() { Name = sourcePoint.Name, Position = sourcePoint.Position, Value = sourcePoint.Value, PublishedDate = DateTime.Now.ToUniversalTime().ToPSTDateTime(), PublishedUser = currentUser.Username, SourcePointId = sourcePoint.Id }; _dbContext.PublishedHistories.Add(history); histories.Add(history); } await _dbContext.SaveChangesAsync(); //Update Table Storage var table = _azureStorageService.GetTable(Constant.PUBLISH_TABLE_NAME); var batchId = Guid.NewGuid(); //A single batch operation can include up to 100 entities, so seperate histories into several batch when histories //https://docs.microsoft.com/en-us/azure/storage/storage-dotnet-how-to-use-tables var batchCount = Math.Ceiling((float)histories.Count() / Constant.AZURETABLE_BATCH_COUNT); var batchTasks = new List <Task <IList <TableResult> > >(); for (int i = 0; i < batchCount; i++) { var historiesPerBatch = histories.Skip(Constant.AZURETABLE_BATCH_COUNT * i).Take(Constant.AZURETABLE_BATCH_COUNT); var batchOpt = new TableBatchOperation(); foreach (var item in historiesPerBatch) { batchOpt.Insert(new PublishStatusEntity(batchId.ToString(), item.SourcePointId.ToString(), item.Id.ToString())); } batchTasks.Add(table.ExecuteBatchAsync(batchOpt)); } Task.WaitAll(batchTasks.ToArray()); IList <SourcePoint> errorSourcePoints = new List <SourcePoint>(); var batchResults = batchTasks.SelectMany(o => o.Result).ToArray(); for (int i = 0; i < batchResults.Count(); i++) { if (!(batchResults[i].HttpStatusCode == 200 || batchResults[i].HttpStatusCode == 204)) { errorSourcePoints.Add(sourcePointList[i]); } } if (errorSourcePoints.Count() > 0) { throw new SourcePointException(sourcePointList, string.Concat(batchResults.Where(o => !(o.HttpStatusCode == 200 || o.HttpStatusCode == 204)).Select(o => o.Result)), null); } //Push message to queue IList <Task> writeQueueTask = new List <Task>(); foreach (var history in histories) { var message = new PublishedMessage() { PublishHistoryId = history.Id, SourcePointId = history.SourcePointId, PublishBatchId = batchId }; writeQueueTask.Add(Task.Run(async() => { await _azureStorageService.WriteMessageToQueue(JsonConvert.SerializeObject(message), Constant.PUBLISH_QUEUE_NAME); await _logService.WriteLog(new LogEntity() { LogId = "10004", Action = Constant.ACTIONTYPE_PUBLISH, ActionType = ActionTypeEnum.AuditLog, PointType = Constant.POINTTYPE_SOURCEPOINT, Message = $"Publish source point named: {history.Name} in the location {history.Position}, value: {history.Value} in the excel file named:{history.SourcePoint.Catalog.Name} by {currentUser.Username}" }); })); } await Task.WhenAll(writeQueueTask); //var publishedHistories = await (from pb in _dbContext.PublishedHistories // where sourcePointIdList.Contains(pb.SourcePointId) // select pb).ToArrayAsync(); foreach (var item in sourcePointList) { item.PublishedHistories = histories.Where(h => h.SourcePointId == item.Id).ToArray(); } return(new PublishSourcePointResult() { BatchId = batchId, SourcePoints = sourcePointList }); } catch (SourcePointException ex) { foreach (var sourcePoint in ex.ErrorSourcePoints) { var logEntity = new LogEntity() { LogId = "10007", Action = Constant.ACTIONTYPE_PUBLISH, ActionType = ActionTypeEnum.ErrorLog, PointType = Constant.POINTTYPE_SOURCEPOINT, Message = ".Net Error", Detail = $"{sourcePoint.Id}-{sourcePoint.Name}-{ex.ToString()}" }; logEntity.Subject = $"{logEntity.LogId} - {logEntity.Action} - {logEntity.PointType} - Error"; await _logService.WriteLog(logEntity); } throw ex; } catch (Exception ex) { var logEntity = new LogEntity() { LogId = "10007", Action = Constant.ACTIONTYPE_PUBLISH, ActionType = ActionTypeEnum.ErrorLog, PointType = Constant.POINTTYPE_SOURCEPOINT, Message = ".Net Error", Detail = ex.ToString() }; logEntity.Subject = $"{logEntity.LogId} - {logEntity.Action} - {logEntity.PointType} - Error"; await _logService.WriteLog(logEntity); throw ex; } }