如何在 Task.Run 内调用异步方法?

How to call Async Method within Task.Run?

我需要以异步方式发送邮件。我想出了使用 Razor Generator 从 Razor 视图生成 Html 模板的方法。现在我需要使用 SmtpClient.SendMailAsync 将 html 作为邮件发送。但我发现 Razor 生成器需要相当长的时间,我不想在我的发送邮件方法中包含模板生成部分,因为发送邮件方法不应该关心获取 Html 模板。

我有示例代码:

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.

此问题是您每次发送电子邮件时都运行以下方法(这会生成初始class,这需要时间)

Engine.Razor.RunCompile

理想情况下,您应该调用以下方法,只有在出现错误时才调用 RunCompile

Engine.Razor.Run

请参阅 this article 了解如何使用带缓存的模板管理器

使用这个:

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