I need to send an asynchronous email from an Async action. I do not understand why the following error is happening, being that I use this same class in other projects and use the same form only without errors, everything quiet.
Error:
The asynchronous action method 'EsqueciMinhaSenhaAsync' returns a Task, which cannot be executed synchronously.
Action:
[AllowAnonymous] [HttpPost, ValidateAntiForgeryToken] public async Task<ActionResult> EsqueciMinhaSenhaAsync(UsuarioEsqueciMinhaSenhaViewModel vModel) { if (ModelState.IsValid) { var conteudo = "este é o conteudo do email"; var nomeRemetente = "esse é o nome do remetente"; if(await EmailService.SendAsync(Language.PasswordRecovery, conteudo, vModel.EmailOuUsername, nomeRemetente)) { TempData["MensagemRetorno"] = Language.EmailSendedWithSuccess; return View("login"); } } TempData["MensagemRetorno"] = Language.ErrorSendingEmail; return View("EsqueciMinhaSenha"); }
My Email Service:
public static async Task<bool> SendAsync(string assunto, string conteudo, string destinatario, string nomeDestinatario) { // Habilitar o envio de e-mail var appSetting = ConfigurationManager.AppSettings; if (appSetting != null && appSetting.Count >= 7 && !string.IsNullOrEmpty(assunto) && !string.IsNullOrEmpty(conteudo) && !string.IsNullOrEmpty(destinatario) && !string.IsNullOrEmpty(nomeDestinatario)) { int port = 0; bool useSSl = false; using (var msg = new MailMessage { From = new MailAddress(appSetting["EmailFrom"], appSetting["EmailNameFrom"]), Body = WebUtility.HtmlEncode(conteudo) }) { int.TryParse(appSetting["EmailPort"], out port); bool.TryParse(appSetting["EmailUseSSL"], out useSSl); msg.ReplyToList.Add(destinatario); msg.To.Add(new MailAddress(destinatario, nomeDestinatario)); msg.Subject = assunto; msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(msg.Body, null, MediaTypeNames.Text.Plain)); msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(msg.Body, null, MediaTypeNames.Text.Html)); using (var smtpClient = new SmtpClient(appSetting["EmailServer"], port)) { var credentials = new NetworkCredential(appSetting["EmailUserName"], appSetting["EmailPassword"]); smtpClient.Credentials = credentials; smtpClient.EnableSsl = useSSl; await smtpClient.SendMailAsync(msg); return await Task.FromResult(true); } } } return await Task.FromResult(false); }
2 Answers
Answers 1
I was having same sort of issue, and when I made all possible path awaitable then issue resolved.
Please make changes to your action EsqueciMinhaSenhaAsync
currently your last line is:
return View("EsqueciMinhaSenha");
change it to
//It looks async/wait pattern expects all paths to have awaitable if async is used
return await View("EsqueciMinhaSenha");
Answers 2
1) Why don't you add sync API version based on SmtpClient.SendMail? https://msdn.microsoft.com/en-us/library/swas0fwc(v=vs.110).aspx
public static bool SendSync(string assunto, string conteudo, string destinatario, string nomeDestinatario) { // Habilitar o envio de e-mail var appSetting = ConfigurationManager.AppSettings; if (appSetting != null && appSetting.Count >= 7 && !string.IsNullOrEmpty(assunto) && !string.IsNullOrEmpty(conteudo) && !string.IsNullOrEmpty(destinatario) && !string.IsNullOrEmpty(nomeDestinatario)) { int port = 0; bool useSSl = false; using (var msg = new MailMessage { From = new MailAddress(appSetting["EmailFrom"], appSetting["EmailNameFrom"]), Body = WebUtility.HtmlEncode(conteudo) }) { int.TryParse(appSetting["EmailPort"], out port); bool.TryParse(appSetting["EmailUseSSL"], out useSSl); msg.ReplyToList.Add(destinatario); msg.To.Add(new MailAddress(destinatario, nomeDestinatario)); msg.Subject = assunto; msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(msg.Body, null, MediaTypeNames.Text.Plain)); msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(msg.Body, null, MediaTypeNames.Text.Html)); using (var smtpClient = new SmtpClient(appSetting["EmailServer"], port)) { var credentials = new NetworkCredential(appSetting["EmailUserName"], appSetting["EmailPassword"]); smtpClient.Credentials = credentials; smtpClient.EnableSsl = useSSl; smtpClient.SendMail(msg); return true; } } } return false; }
2) Another option is to use IAsyncOperation as a returning result of your email service. That way, you can use this as both async way (via await) and sync way like that:
var asyncOp = EmailService.SendAsync(some-params-here); var task = asyncOp.AsTask(); task.Wait(); return task.Result; // TODO it's nice to care about exceptions too!
0 comments:
Post a Comment