0

how to call Call Async Methods in Parallel.ForEach loop properly.billDataService.SaveBillDetail and GetProfileDetails both are async methods.data saving in MongoDB in SaveBillDetail .

public async Task ConvertXMLFileToJSON()
        {
            try
            {

                if (Directory.Exists(_appSettings.DocumentsStorage))
                {
                    int i = 1; //Test
                    bool exists = Directory.GetFiles(_appSettings.DocumentsStorage).Any(x => x.Equals(Path.Combine(_appSettings.DocumentsStorage, "Ready.txt"), StringComparison.OrdinalIgnoreCase)); //Need to check
                    if (exists)
                    {
                      Parallel.ForEach(System.IO.Directory.GetFiles(_appSettings.DocumentsStorage, "*.xml"), (currentFile) =>
                        {
                            try
                            {
                                XElement root = XElement.Load(currentFile); // or .Parse(string);
                                //Removing CDATA property from XElement.
                                XElement items = XElement.Parse(root.ToString().Replace("<![CDATA", "").Replace("]]>", "").Replace("[", ""));
                                //Removing XML_INFO Tag from XElement.
                                items.Elements("XML_INFO").Remove();
                                XmlDocument xmlDoc = new XmlDocument();
                                using (XmlReader xmlReader = items.CreateReader())
                                {
                                    xmlDoc.Load(xmlReader);
                                }

                                var json = JsonConvert.SerializeXmlNode(xmlDoc);
                                billDetails obj = JsonConvert.DeserializeObject<billDetails>(json);
                                BillDetails billDetails = new BillDetails();
                                billDetails.AccountNumber = obj.BILL_INFO.BILL_RUN.ACCT_INFO.ACCT_CODE;
                                billDetails.MobileNumber = obj.BILL_INFO.BILL_RUN.ACCT_INFO.PRINCIPAL_NO.STR_PRINCIPAL_NO;
                                billDetails.BillDate = DateTime.ParseExact(obj.BILL_INFO.BILL_RUN.BILL_PROP.TO_DATE, "dd/MM/yyyy", CultureInfo.InvariantCulture);
                                billDetails.DueAmount = obj.BILL_INFO.BILL_RUN.ACCT_INFO.ACCT_BALANCE_TRACE.TOTAL_DUE;
                                billDetails.CustomerName = obj.BILL_INFO.BILL_RUN.CUST_INFO.CUST_NAME.FULL_NAME;
                                billDetails.InvoiceId = obj.BILL_INFO.BILL_RUN.BILL_PROP.INVOICE_ID;
                                billDetails.DueDate = DateTime.ParseExact(obj.BILL_INFO.BILL_RUN.BILL_PROP.DUE_DATE, "yyyyMMdd hh:mm:ss", CultureInfo.InvariantCulture);
                                billDetails.RepositoryName = "postpaid";
                                billDetails.BillRun = obj.BILL_INFO.BILL_RUN; //tempObj2.BILL_INFO.ToString().Remove(0, 1);
                                billDetails.ObjectId = Guid.NewGuid().ToString();
                                if (billDetails != null)
                                {
                                    BillDataService billDataService = new BillDataService(_dbConfig);
                                    Console.WriteLine("SaveBillDetail");
                                    if (billDataService.SaveBillDetail(billDetails) != null)
                                    {
                                        Console.WriteLine("SaveBillDetail done");
                                        GetProfileDetails(billDetails);
                                        _logger?.LogInformation(i++ + "  File Success");
                                        Console.WriteLine(i++ + "  File Success");
                                        // File.Delete(file);  //Delete File 
                                    }
                                }

                            }
                            catch (Exception ex)
                            {
                                _logger?.LogError(ex, "Error");
                            }
                            finally { }
                        });
                    }
                }
            }

            catch (Exception ex)
            {
                _logger?.LogError(ex, "Error");
            }
            finally
            {

            }
        }


public async Task GetProfileDetails(BillDetails billDetails)
        {
            try
            {
                ProfileService profileService = new ProfileService(_dbConfig);
                var searchFilter = new SearchFilter
                {
                    Filters = new List<Filter>()
                };

                if (!string.IsNullOrEmpty(billDetails.AccountNumber))
                {
                    searchFilter.Filters.Add(new Filter() { PropertyName = "AccountNumber", Operator = Operator.Equals, Value = billDetails.AccountNumber, CaseSensitive = true });
                }

                if (searchFilter != null)
                {
                    Profile profile = await profileService.GetProfiles(searchFilter);
                    if (profile != null)
                    {
                        await SendMailNotification(profile, billDetails);
                    }
                    else
                    {
                        _logger?.LogError("Profile Info not found");

                    }
                }
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "Error");
                throw;
            }
            finally { }
        }


normal for each loop I can able to call and save data in MongoDB.but Parallel.ForEach loop I cannot able to call the async method using await and data saving in mongo also not working.inside Parallel.ForEach loop I avoided using await of the front of the calling method.

nani
  • 15
  • 2
  • 6

1 Answers1

0

You can change your code to be like below and wait for all the tasks to be completed.

var fileTasks = System.IO.Directory.GetFiles(_appSettings.DocumentsStorage, "*.xml").Select(async currentFile =>
                        {
                            try
                            {
                                XElement root = XElement.Load(currentFile); // or .Parse(string);
                                // rest o your code here
                                if (billDetails != null)
                                {
                                    if (billDataService.SaveBillDetail(billDetails) != null)
                                    {
                                        Console.WriteLine("SaveBillDetail done");
                                        await GetProfileDetails(billDetails);
                                    }
                                }
                             }
                          catch(exception ex) { //log exeption }
                       });

await Task.WhenAll(fileTasks);
Rahul
  • 76,197
  • 13
  • 71
  • 125
  • It's working but no change. performance is the same compare to normal for each loop. – nani May 22 '20 at 09:08