2016-08-22 185 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