2016-08-22 181 views
-2

我需要以異步方式發送郵件。我已經想出了使用Razor Generator從剃刀視圖生成Html模板。現在我需要使用SmtpClient.SendMailAsync將Mail作爲Mail發送。但我發現Razor生成器需要相當多的時間,我不希望在我的發送郵件方法中包含模板生成部分,因爲發送郵件方法不應該關心獲取Html模板。如何在Task.Run中調用異步方法?

我的示例代碼:

public static void SendEmailAsync<TModel>(TModel model, string templatePath, string subj, string toEmail, string cc = null, string bcc = null) 
    { 

     string templateFilePath = HostingEnvironment.MapPath(templatePath); 
     // Generate the email body from the template file. 
     // 'templateFilePath' should contain the absolute path of your template file. 
     if (templateFilePath != null) 
     { 
      Task.Run(() => 
      { 
       var emailHtmlBody = Engine.Razor.RunCompile(File.ReadAllText(templateFilePath), 
       templateFilePath, model.GetType(), model); 
       SendEmailAsync(subj, emailHtmlBody, toEmail, cc, bcc); 
      }); 
     } 
     else 
     { 
      throw new System.Exception("Could not find mail template."); 
     } 
    } 

和SendMailAsync的簽名是:

static async Task SendEmailAsync(string subj, string message, string toEmail, string cc = null, string bcc = null) 
    { 
     //Reading sender Email credential from web.config file 
     string fromEmail = ConfigurationManager.AppSettings["FromEmail"].ToString(); 
     string fromName = ConfigurationManager.AppSettings["FromName"].ToString(); 

     //creating the object of MailMessage 
     MailMessage mailMessage = new MailMessage(); 
     mailMessage.From = new MailAddress(fromEmail, fromName); //From Email Id 
     mailMessage.Subject = subj; //Subject of Email 
     mailMessage.Body = message; //body or message of Email 
     mailMessage.IsBodyHtml = true; 

     string[] toMuliId = toEmail.Split(','); 
     foreach (string toEMailId in toMuliId) 
     { 
      mailMessage.To.Add(new MailAddress(toEMailId)); //adding multiple TO Email Id 
     } 


     if (cc != null) 
     { 
      string[] ccId = cc.Split(','); 

      foreach (string ccEmail in ccId) 
      { 
       mailMessage.CC.Add(new MailAddress(ccEmail)); //Adding Multiple CC email Id 
      } 
     } 

     if (bcc != null) 
     { 
      string[] bccid = bcc.Split(','); 

      foreach (string bccEmailId in bccid) 
      { 
       mailMessage.Bcc.Add(new MailAddress(bccEmailId)); //Adding Multiple BCC email Id 
      } 
     } 

     SmtpClient smtp = new SmtpClient 
     { 
      EnableSsl = true, 
      Credentials = new NetworkCredential("", "") 
     }; 

     //network and security related credentials 
     await smtp.SendMailAsync(mailMessage); //sending Email 
    } 

沒有異常拋出,但我得到的錯誤:

System.InvalidOperationException: An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%@ Page Async="true" %>. This exception may also indicate an attempt to call an "async void" method, which is generally unsupported within ASP.NET request processing. Instead, the asynchronous method should return a Task, and the caller should await it.

+0

基本的問題似乎是你的'st atic void SendEmailAsync (...)'方法應該是靜態異步任務SendEmailAsync (...)'而不是。這樣,你可以'等待'Task.Run()'。這與之前提出的許多問題中所討論的問題完全相同,包括標記的副本。 –

+0

@PeterDuniho我只是不想繼續添加async關鍵字到我的所有方法直到控制器。 –

+0

@Aron是的,謝謝我認爲這是同一個問題。 –

回答

0

使用這個:

await Task.Run(async() => 
{ 
    await DoAsyncMethodAsync(); 
}); 
+0

或者,您可以直接返回'DoAsyncMethodAsync()'。 – Aron

+0

@Aron,你的意思是'等待Task.Run(DoAsyncMethodAsync())'? –

+0

@MikeHenry不,我不知道。我想你的意思是'等待Task.Run(DoMethodAsync)'。 – Aron

0

這個問題您每次發送電子郵件時都會運行以下方法(這會生成所需的初始類的時間)

Engine.Razor.RunCompile 

理想情況下,你應該調用下面的方法只有到那時,如果拋出一個錯誤,然後調用RunCompile

Engine.Razor.Run 

this article上使用模板管理器與緩存

+1

理想情況下,您在編譯時預編譯Razor ...> _ < – Aron

+0

我一直懶惰地根據需要加載模板,另外我運行一個文件觀察器來對照模板目錄,根據需要使模板高速緩存失效,因此對模板的更新反映在實際而不必擔心重新編譯該項目:) – timkly