【问题标题】:ASP.NET Identity Send Email: TaskCanceledExceptionASP.NET 身份发送电子邮件:TaskCanceledException
【发布时间】:2014-08-19 20:53:11
【问题描述】:

我正在尝试在 asp.net 身份 2.0 应用程序中发送验证电子邮件地址电子邮件,但收到 TaskCanceledException 错误。

我尝试了这个帖子中的内容:Asp.Net Identity 2.0 - How to Implement IIdentityMessageService to do Async SMTP using SmtpClient?

如果我使用await,应用程序将永远运行:没有错误消息。但第二个选项返回错误。

错误抛出于:return smtpClient.SendMailAsync(msg);

IdentityConfig.cs

    public async Task SendAsync(IdentityMessage message)
    {
        // Plug in your email service here to send an email.

        try
        {
            #region formatter
            string text = string.Format("Please click on this link to {0}: {1}", message.Subject, message.Body);
            string html = "Please confirm your account by clicking this link: <a href=\"" + message.Body + "\">link</a><br/>";

            html += HttpUtility.HtmlEncode(@"Or click on the copy the following link on the browser:" + message.Body);
            #endregion

            MailMessage msg = new MailMessage();
            msg.From = new MailAddress("");
            msg.To.Add(new MailAddress(message.Destination));
            msg.Subject = message.Subject;
            msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(text, null, MediaTypeNames.Text.Plain));
            msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(html, null, MediaTypeNames.Text.Html));

            using (var smtpClient = new SmtpClient())
            {
                smtpClient.EnableSsl = true;
                smtpClient.SendCompleted += (s, e) => { smtpClient.Dispose(); };
                await smtpClient.SendMailAsync(msg);
            }


        }
        catch (Exception ex)
        {

            throw ex;
        }


    }

注册.aspx.cs

        protected void CreateUser_Click(object sender, EventArgs e)
    {
        var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
        var user = new ApplicationUser()
        {
            UserName = Email.Text,
            Email = Email.Text,
            UserProfileInfo = new UserProfileInfo
            {
                FirstName = Firstname.Text,
                LastName = Lastname.Text,
                Adress = Adress.Text,
                Zip = Zip.Text,
                City = City.Text,
                Mobile = Mobile.Text

            }

        };
        IdentityResult result = manager.Create(user, Password.Text);
        if (result.Succeeded)
        {
            // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
            string code = manager.GenerateEmailConfirmationToken(user.Id);
            string callbackUrl = IdentityHelper.GetUserConfirmationRedirectUrl(code, user.Id, Request);
            manager.SendEmail(user.Id, "Confirm your account", "Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>.");

            manager.AddToRole(user.Id, "Konsument");
            IdentityHelper.SignIn(manager, user, isPersistent: false);
            IdentityHelper.RedirectToReturnUrl(Request.QueryString["ReturnUrl"], Response);
        }
        else
        {
            ErrorMessage.Text = result.Errors.FirstOrDefault();
        }
    }

【问题讨论】:

    标签: c# asp.net .net asp.net-identity smtpclient


    【解决方案1】:

    @ntl 正确识别了问题:SmtpClient 实例在请求完成之前被释放。不过,我更喜欢使用asyncawait 作为解决方案:

    public async Task SendAsync(IdentityMessage message)
    {
      ...
      using (var smtpClient = new SmtpClient())
      {
        smtpClient.EnableSsl = true;
        smtpClient.SendCompleted += (s, e) => { smtpClient.Dispose(); };
        await smtpClient.SendMailAsync(msg);
      }
    }
    

    那么,让我们解决原来的问题:

    如果我使用 await 应用程序将永远运行:没有错误消息。

    我感觉你的代码在调用SendAsync 之后可能会调用Task.WaitTask&lt;T&gt;.Result。这才是真正的问题:调用代码应该改为使用await(这使得调用方法async 并返回Task/Task&lt;T&gt;,这使得its调用代码必须使用await 等)。让async 通过代码库自然地“成长”。这就是为什么我的MSDN article on the subject 中的async 最佳实践之一是“一路异步”。

    造成死锁是因为当您await 一个任务时,await 将默认捕获“当前上下文”(在本例中为 ASP.NET SynchronizationContext),并使用该上下文来恢复async 方法。但是,ASP.NET SynchronizationContext 一次只允许每个请求一个线程,因此当调用代码阻塞(通过调用WaitResult)时,它阻塞了一个线程在这种情况下,async 方法无法恢复。我更详细地描述了这种死锁情况on my blog

    最好的办法是用await,一路用async

    【讨论】:

    • 仍然永远运行
    • @MaddePersson:请提供重现问题的最小代码示例。
    • 我更新了我的代码,并包含了 register.aspx.cs 代码。
    • @MaddePersson:您的代码没有调用SendAsync。您需要做的是 1) 复制您现有的解决方案。 2)在保持死锁的同时删除所有代码。 3)发布所有剩余的代码。
    • 不明白。我刚从身份开始,之前没有处理过任务和异步
    【解决方案2】:

    问题可能是在执行 SendMailAsync 时您的 smpt 客户端已经被释放。这就是引发异常的原因,但由于此操作在单独的线程(异步)中运行,您会得到 TaskCanceledException。

    您可以尝试删除您的 using 语句。

    public Task SendAsync(IdentityMessage message)
    {
        // Plug in your email service here to send an email.
        try
        {
            #region formatter
            string text = string.Format("Please click on this link to {0}: {1}", message.Subject, message.Body);
            string html = "Please confirm your account by clicking this link: <a href=\"" + message.Body + "\">link</a><br/>";
            html += HttpUtility.HtmlEncode(@"Or click on the copy the following link on the browser:" + message.Body);
            #endregion
    
            MailMessage msg = new MailMessage();
            msg.From = new MailAddress("info@emailadress.com");
            msg.To.Add(new MailAddress(message.Destination));
            msg.Subject = message.Subject;
            msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(text, null, MediaTypeNames.Text.Plain));
            msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(html, null, MediaTypeNames.Text.Html));
    
            var smtpClient = new SmtpClient();            
            smtpClient.EnableSsl = true;
            smtpClient.SendCompleted += (s, e) => { smtpClient.Dispose(); };
            return smtpClient.SendMailAsync(msg);
        }
        catch (Exception)
        {
            return Task.FromResult(0);
        }
    }
    

    Smtp 客户端将在 SendCompleted 处理程序的帮助下进行处理。

    【讨论】:

    • 永远等待本地主机。如果我得到你的工作答案,我喜欢它,它很简单。
    • MailMessage 也应该被释放......也许你只是想保持这个同步......
    猜你喜欢
    • 2016-10-04
    • 2012-12-11
    • 2016-09-15
    • 1970-01-01
    • 2020-09-08
    • 2018-08-07
    • 2013-11-30
    • 1970-01-01
    • 2012-07-27
    相关资源
    最近更新 更多