2014-10-11 474 views
0

考虑以下代码:消防与异步忘记

public async Task<Status> SendMessage(Message message) 
{ 
    List<IMessage> _messageDispatchers = new List<IMessage>(); 
    try 
    { 
     Object[] args = new Object[] { _message }; 
     IMessage endpoint = (IMessage)Activator.CreateInstance(Type.GetType(_message.AgentDLLName), args); 
     _messageDispatchers.Add(endpoint); 

     foreach (IMessage dispatcher in _messageDispatchers) 
     { 
      await Task.Run(() => dispatcher.SendMessage(_message)); 
     } 
     return await Task.Run(() => Status.Success); 
    } 
    catch (Exception ex) 
    { 
     logger.Log(LoggerLevel.Error, ex.Message); 
     return Status.EmailSendingFailed; 
    } 

} 

的SendMessage函数:

public async Task<Status> SendMessage(OutboundMessage outboundmessage) 
{ 
    string strMessage = string.Empty; 
    string subject = string.Empty; 
    MessageServices objService = new MessageServices(); 
    try 
    { 
     var config = (from SmtpConfigurationElement ms in AppConfiguration.Instance.Smtps 
         where ms.Key == "smtp" 
         select ms).Single(); 

     SmtpClient smtpClient = new SmtpClient(config.Host); 
     smtpClient.Port = Convert.ToInt32(config.port); 
     smtpClient.EnableSsl = true; 
     smtpClient.Credentials = new NetworkCredential(config.UserName, config.Password); 

     string[] strToList = outboundmessage.ToList.Split(';'); 
     MailMessage mail = new MailMessage(); 
     mail.From = new MailAddress(outboundmessage.FromAddress); 

     if (strToList.Length > 0) 
     { 
      for (int j = 0; j < strToList.Length; j++) 
      { 
       mail.To.Add(strToList[j]); 
      } 
     } 
     else 
     { 
      _LOGGER.Log(LoggerLevel.Information, "SMTP Mail Send failed as ToList is not correct"); 
      return Status.Failed; 
     } 

     if (!string.IsNullOrEmpty(outboundmessage.CCList)) 
     { 
      string[] strCCList = outboundmessage.CCList.Split(';'); 
      if (strCCList.Length > 0) 
      { 
       for (int k = 0; k < strCCList.Length; k++) 
       { 
        mail.CC.Add(strToList[k]); 
       } 
      } 
     } 

     if (!string.IsNullOrEmpty(outboundmessage.Attachments)) 
     { 
      System.Net.Mail.Attachment attachment; 
      attachment = new System.Net.Mail.Attachment(outboundmessage.Attachments); 
      mail.Attachments.Add(attachment); 
     } 

     strMessage = await objService.ReplaceMessageWithPlaceholders(outboundmessage.PlaceholderValues, outboundmessage.MessageBody); 
     subject = await objService.ReplaceMessageWithPlaceholders(outboundmessage.PlaceholderValues, outboundmessage.Subject); 
     mail.Body = strMessage; 
     mail.Subject = subject; 
     mail.IsBodyHtml = true; 
     await Task.Run(() => smtpClient.Send(mail)); 


     return Status.Success; 
    } 
    catch (Exception ex) 
    { 
     return Status.Failed; 
    } 
} 

并调用SendMessage函数:

public Status MarketingEmail(OutboundMessage _message) 
{ 
    try 
    { 
     _message.MessageCreatedDate = System.DateTime.Now; 
     processor.SendMessage(_message); 
     return Status.Success; 
    } 
    catch (Exception ex) 
    { 
     _LOGGER.Log(LoggerLevel.Error, "Error in Marketing Email" + ex.ToString()); 
     return Status.InsertFailed; 
    } 
} 

整个想法是做一个工作流程其中发送电子邮件是最后一项任务,这应该是一个失火和遗忘的事情。

现在调用processor.SendMessage(_message)具有这样的建议:

由于此呼叫不被期待已久的,在完成该呼叫之前,在当前的方法 的继续执行。考虑将“await” 运算符应用于调用的结果。

这是一个有效的事情,因为异步&等待需要一起使用。

问题:

  1. 将没有任何麻烦的现行办法的工作,如果该建议被忽略? (我在开发阶段问这个,因为这仍然是我现在可以建议的设计变更,而不是后来遇到任何严重问题。)
  2. 什么是设计工作流中的建议的最佳实践时应考虑到上述要求?
+0

是'Status.Success'一个枚举?如果你不应该这样做'Task.Run(()=> Status.Success)''不返回Task.FromResult(Status.Success)'或'刚刚返回Status.Success;'为approprate,无需启动完成任务并等待它。 – 2014-10-11 05:04:52

回答

3

目前的方法将“继续工作”,因为它将继续到return Status.Success;而不用等待processor.SendMessage(_message);的呼叫完成。

然而,由于电话被解雇&遗忘,那SendMessage过载不会做的catch块中的任何记录,您运行电子邮件不能被发送的风险,但没有人收到通知了。

异步电子邮件发送的一种常用方法是:将电子邮件存储在其他地方(通常是消息队列或数据库),然后设置一个单独的异步进程来读取排队的电子邮件并发送它们。如果成功,它会将电子邮件标记为已发送。如果失败,再次尝试(达到一定的时间限制或重试#),然后如果它放弃,它可以触发一个通知或设置以后可检查的标志。

那么你的代码将基本上可说:“没关系,电子邮件已成功排队”,而不是“没关系,电子邮件发送”。将实际发送移动到单独的过程要可靠得多。

+0

P.S.如果您要实现电子邮件排队方式,您可能会试图将“MailMessage”序列化为JSON并以此方式进行保存。但它不会反序列化回'MailMessage'情况下,因为'MailAddress'类,它'MailMessage'内部使用,没有一个参数的构造函数。有办法可以解决这个问题,但是我们发现将邮件保存到数据库表中更容易,其中包含Subject,From,To,CC,BCC,Body,DateCreated,DateSent等离散列。希望这可以帮助。 – 2014-10-11 05:23:19

+0

这个答案是正确的,但不清楚什么时候“但没人接到通知”。技术上的原因是,如果没有'await',.NET CLR将不会将异常(如果有的话)传递回调用者线程,并且异常会自动放弃。因此,C#编译器会生成警告以明确警告开发人员。 – 2014-10-11 09:14:32