2017-03-31 55 views
0

正在开发一种新的post方法。我发现我在瓶颈foreach声明中遇到了极其漫长的等待时间。我节省了5到8K(取决于发送的项目)到数据库。该方法成功,但通常需要60秒以上的时间。我一直在研究如何实际执行一个异步方法,但我不确定这实际上能够解决问题。在foreach中实现异步.net 4.5 mvc

这是完整的方法

[HttpPost] 
     public ActionResult ConfirmSend(int? SystemGeneralAnnouncementId) { 
     var systemGeneralAnnouncement = (SystemGeneralAnnouncementId == null) ? null : _uow.SystemGeneralAnnouncementRepository.GetById(SystemGeneralAnnouncementId.Value); 
     List<Status> status = new List<Status>(); 

      if (systemGeneralAnnouncement.Statuses.Length > 0) 
      { 
       status.AddRange(systemGeneralAnnouncement.Statuses.Split(',').Select(item => (Status) Enum.Parse(typeof (Status), item))); 
      } 

      var allEmailAddresses = new List<PointOfContact>(); 
      var EmailAddresses = new List<PointOfContact>(); 


      var result = new List<PointOfContact>(); 
      foreach (var item in status) 
      { 
       result = _uow.PointOfContactRepository.GetAllByStatus(item).ToList(); 
       allEmailAddresses.AddRange(result); 
      } 


      if (systemGeneralAnnouncement.SendToRecipients.Contains("(1) All Three Contact Types")) 
      { 
       mailAddresses = allEmailAddresses; 
      } 
      else 
      { 
       if (systemGeneralAnnouncement.SendToRecipients.Contains("(2) All Contacts ")) 
       { 
        EmailAddresses.AddRange(allEmailAddresses.Where(r => r.PointOfContactType == PointOfContactTypes.Primary).ToList()); 
       } 
       if (systemGeneralAnnouncement.SendToRecipients.Contains("(3) All Compliance contacts")) 
       { 
        pocEmailAddresses.AddRange(allEmailAddresses.Where(r => r.PointOfContactType == PointOfContactTypes.Secondary).ToList()); 
       } 
       if (systemGeneralAnnouncement.SendToRecipients.Contains("(4) All Authorities")) 
       { 
        pocEmailAddresses.AddRange(allEmailAddresses.Where(r => r.PointOfContactType == PointOfContactTypes.SigningAuthority).ToList()); 
       } 
       if (systemGeneralAnnouncement.SendToRecipients.Contains("(5) All Rate Contacts")) 
       { 
        EmailAddresses.AddRange(allEmailAddresses.Where(r => r.PointOfContactType == PointOfContactTypes.TuitionRates).ToList()); 
       } 
       if (systemGeneralAnnouncement.SendToRecipients.Contains("(6) Specified Email Address")) 
       { 
        var pocs = new List<PointOfContact>(); 

        string[] emails = systemGeneralAnnouncement.EmailAddresses.Split(','); 

        foreach (string email in emails) 
        {      
         var addContact = new InstitutionPointOfContact { Email = email }; 

         User user = _uow.UserRepository.GetByEmail(email); 

         if (user == null) 
         { 
          addContact.FirstName = "Not Created Account Yet"; 
         } 
         else 
         { 
          addContact.FirstName = user.FirstName; 
          addContact.LastName = user.LastName; 
         } 

         List<PointOfContact> idAssociatedToUser = 
          _uow.PointOfContactRepository 
           .GetAllByEmail(email) 
           .ToList(); 


         if (idAssociatedToUser.Count == 0) 
         { 
          addContact.IDNumber = "N/A"; 
         } 
         else 
         { 
          string[] opeidArray = opeidAssociatedToUser 
           .Select(x => x.OPEIDNumber) 
           .ToArray(); 

          addContact.OPEIDNumber = string.Join(",", opeidArray); 
         } 
         Contacts.Add(addContact); 
        }     
        EmailAddresses.AddRange(Contacts); 
       } 
      } 

具体Foreach

if (EmailAddresses.Count > 0) 
       { 
        foreach (PointOfContact emailAddress in EmailAddresses.Where(x => x.Email != "").ToList()) 
        { 
         string firstName = emailAddress.FirstName == null ? "" : emailAddress.FirstName.Trim(); 
         string lastName = emailAddress.LastName == null ? "" : emailAddress.LastName.Trim(); 

         string userName = firstName + " " + lastName; 

         string emailBody = WebUtility.HtmlDecode(systemGeneralAnnouncement.EmailBody); 

         SaveToDatabase(emailAddress.Email, emailBody, systemGeneralAnnouncement.Subject, UserIdentityHelper.GetUserEmailAddress + " (" + UserIdentityHelper.GetUserId + ")", systemGeneralAnnouncement.SystemGeneralAnnouncementId, userName, emailAddress.OPEIDNumber); 
         LogInstitutionEmail(systemGeneralAnnouncement.Subject, emailBody, emailAddress.Email, emailAddress.OPEIDNumber, systemGeneralAnnouncement.EmailAttachmentLocation); 
        } 
       } 
       return View("GeneralAnnouncementGeneratedConfirmation"); 
      } 

和数据库的方法:

 private void LogInstitutionEmail(string subject, string emailBody, string email, string opeidNumber, string emailAttachment) 
     { 
      try 
      { 
       using (var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["MasterContext"].ConnectionString)) 
       { 
        conn.Open(); 
        var cmd = new SqlCommand("Insert Into InstitutionEmails (Since, Subject, Email, EmailAddress, OpeidNumber, FirstReadDateTime, Attachment) VALUES(@Since, @Subject, @Email, @EmailAddress, @idNumber, NULL, @Attachment)", conn); 
        cmd.CommandType = CommandType.Text; 
        cmd.Parameters.Add(new SqlParameter() { ParameterName = "@Since", Value = DateTime.Now }); 
        cmd.Parameters.Add(new SqlParameter() { ParameterName = "@Subject", Value = subject }); 
        cmd.Parameters.Add(new SqlParameter() { ParameterName = "@Email", Value = emailBody }); 
        cmd.Parameters.Add(new SqlParameter() { ParameterName = "@EmailAddress", Value = email }); 
        cmd.Parameters.Add(new SqlParameter() { ParameterName = "@idNumber", Value = idNumber }); 

        if (!string.IsNullOrEmpty(emailAttachment)) 
        { 
         cmd.Parameters.Add(new SqlParameter() { ParameterName = "@Attachment", Value = emailAttachment }); 
        } 

        cmd.ExecuteNonQuery(); 
        conn.Close(); 
       } 
      } 
      catch (Exception ex) 
      { 
      } 
     } 

     private void SaveToDatabase(string emailRecipient, string emailBody, string subject, string userWhoSentIt, int systemGeneralAnnouncementId, string userName, string opeidNumber) 
     { 
      try 
      { 
       using (var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["MasterContext"].ConnectionString)) 
       { 
        conn.Open(); 
        var cmd = new SqlCommand("Insert Into EmailQueue (EmailRecipients, EmailBody, EmailSubject, UserWhoSentIt, QueueDate, SystemGeneralAnnouncementId, UserName, idNumber) VALUES(@EmailRecipients, @EmailBody, @EmailSubject, @UserWhoSentIt, @QueueDate, @SystemGeneralAnnouncementId, @UserName, @idNumber)", conn); 
        cmd.CommandType = CommandType.Text; 
        cmd.Parameters.Add(new SqlParameter() {ParameterName = "@EmailRecipients", Value = emailRecipient }); 
        cmd.Parameters.Add(new SqlParameter() { ParameterName = "@EmailBody", Value = emailBody }); 
        cmd.Parameters.Add(new SqlParameter() { ParameterName = "@EmailSubject", Value = subject }); 
        cmd.Parameters.Add(new SqlParameter() { ParameterName = "@UserWhoSentIt", Value = userWhoSentIt }); 
        cmd.Parameters.Add(new SqlParameter() { ParameterName = "@QueueDate", Value = DateTime.Now }); 
        cmd.Parameters.Add(new SqlParameter() { ParameterName = "@SystemGeneralAnnouncementId", Value = systemGeneralAnnouncementId }); 
        cmd.Parameters.Add(new SqlParameter() { ParameterName = "@UserName", Value = userName }); 
        cmd.Parameters.Add(new SqlParameter() { ParameterName = "@idNumber", Value = idNumber }); 


        cmd.ExecuteNonQuery(); 
        conn.Close(); 
       } 
      } 
      catch (Exception ex) 
      { 
      } 
     } 

我的问题是双重的。首先,我在研究中注意到,这种类型的代码(使用Sql server 2012)是异步可行的选择,如果您有数据库级别的瓶颈,异步可能会导致死锁。其次,如果异步/等待是可行的,那么实际执行它的最好方法是什么?

更新:post方法只是检索SystemGeneralAnnouncement的Id,以及启动该方法的确认。所有的实际执行都在方法本身内部处理。

更新2:对于澄清清酒,这些项目被传递给任务调度是火灾在以后的日子,并采取队列中的所有存储的项目,然后提供他们的背景。这就是我使用SQL调用的原因。

+2

如果您执行异步/等待它将需要从底部到顶部完成。这是您调用的主要异步方法将在ADO.Net中,并且当您添加'await'时,您将使该方法成为'async',并且这会引发您的控制器。然后,您会想要对控制器进行ajax调用,以使整个往返行程异步。 – juharr

+0

@jpears,好吧,如果你想优化你的查询,你可能不应该在循环中打你的数据库,因为每次调用你都会得到很多额外的延迟。最重要的是,将电子邮件作为文本存储在文件系统上可能会更好,只需将路径存储到文本文件 –

+0

@ johnny5感谢您的回复。如果我要将SavetoDatabase和LogInstitutionEmail方法移到循环之外,是否仍然最好将它们放入异步方法中? – jpears

回答

0

如果你有一个数据库级的瓶颈,异步可能导致死锁

不是。

但是,async不会帮助您更快地运行 - 这是一个常见的误解。

你想要做的是批量更新。

+0

Stephen Cleary。我阅读了关于这个主题的一些博客文章,感谢您澄清错误观念。正如约翰尼指出的那样,我觉得我需要将这个呼叫移到foreach之外。我将研究使用批量更新。 – jpears

+0

我目前无法注册。我会尽快这样做。 – jpears