2014-10-11 20 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