c# - 始终使用异步/等待在 ASP.NET Web 窗体中的浏览器中加载页面

标签 c# asp.net async-await task-parallel-library

我正在使用 ASP.NET Web 窗体发送两封电子邮件,发送两封电子邮件后,我将从系统中删除该文件。我的代码使用 async/await,它在控制台应用程序中工作正常,但是当我将相同的代码移动到 asp.net web 表单时,它正在发送电子邮件,但在 Task.WaitAll(emailSender1, emailSender2) 之后我没有收到任何响应,结果,文件没有被删除,浏览器总是看到加载。我试图解决这个问题,但最终无法解决。我需要有人帮助解决问题或任何可以完成的替代方法。我的代码如下:

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" Async="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication1.Default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div> 
        <asp:Button ID="btnSendEmail" runat="server" Text="Send Email" OnClick="btnSendEmail_Click" />
    </div>
    </form>
</body>
</html>

Default.aspx.cs 代码隐藏

using System;

namespace WebApplication1
{
    public partial class Default : System.Web.UI.Page
    {
        private static string filePath = @"C:\Uploads\";
        protected void Page_Load(object sender, EventArgs e)
        {
        }

        protected void btnSendEmail_Click(object sender, EventArgs e)
        {
            Sender mailSender = new Sender();
            mailSender.SendEmail("myfirstemail@gmail.com", "mysecondemail@gmail.com", "Async mail with attachment", "Async mail with attachment body goes here ...", filePath + "TestFile.txt");
            Response.Redirect("Succcess.apsx");
        }
    }
}

Sender.cs

using System.IO;
using System.Net.Mail;
using System.Text;
using System.Threading.Tasks;

namespace WebApplication1
{
    public class Sender
    {
        public void SendEmail(string toEmail, string logMail, string title, string body, string attachmentPath)
        {
            var emailSender1 = SendEmailAsync(toEmail, title, body, attachmentPath);
            var emailSender2 = SendEmailAsync(logMail, "Copy of " + title, body, attachmentPath);

            Task.WaitAll(emailSender1, emailSender2);

            // deleting file
            File.Delete(attachmentPath);
        }
        public async Task SendEmailAsync(string toEmail, string title, string body, string attachmentPath)
        {
            // class to hold all values from the section system.net/mailSettings/smtp in app.config
            MailConfiguration smtpSection = new MailConfiguration();
            using (MailMessage mailMsg = new MailMessage("<" + smtpSection.FromAddress + ">", toEmail))
            {
                mailMsg.IsBodyHtml = true;
                mailMsg.Subject = title;
                mailMsg.SubjectEncoding = Encoding.UTF8;
                mailMsg.Body = body;
                mailMsg.BodyEncoding = Encoding.UTF8;

                if (!string.IsNullOrWhiteSpace(attachmentPath) && File.Exists(attachmentPath))
                {
                    Attachment attachment = new Attachment(attachmentPath);
                    mailMsg.Attachments.Add(attachment);
                }
                using (SmtpClient smtpClient = new SmtpClient())
                {
                    smtpClient.Timeout = 1000000;
                    smtpClient.UseDefaultCredentials = false;
                    await smtpClient.SendMailAsync(mailMsg);
                }
            }
        }
    }
}

MailConfiguration.cs

public class MailConfiguration
    {
        private SmtpSection smtpSection = (ConfigurationManager.GetSection("system.net/mailSettings/smtp")) as SmtpSection;

        public string ConfigurationFileName
        {
            get
            {
                try
                {
                    return smtpSection.ElementInformation.Source;
                }
                catch (Exception)
                {
                    return "";
                }
            }
        }

        public string FromAddress
        {
            get
            {
                return smtpSection.From;
            }
        }

        public string Host
        {
            get
            {
                return smtpSection.Network.Host;
            }
        }

        public int Port
        {
            get
            {
                return smtpSection.Network.Port;
            }
        }

        public int TimeOut
        {
            get
            {
                return 2000;
            }
        }

        public override string ToString()
        {
            return "From: [" + FromAddress + "] Host: [" + Host + "] Port: [" + Port + "]";
        }
    }

最佳答案

经过this article之后我开始知道控制台应用程序使用线程池 SynchronizationContext,而 GUI 或 ASP.NET 使用一次一个 block 的 SynchronizationContext。这意味着死锁的主要原因是 Task.WaitAll(emailSender1, emailSender2)。根据文章,我将这行代码更改为await Task.WhenAll(emailSender1, emailSender2)。更正的解决方案是:

Default.aspx.cs 代码隐藏

using System;

namespace WebApplication1
{
    public partial class Default : System.Web.UI.Page
    {
        private static string filePath = @"C:\Uploads\";
        protected void Page_Load(object sender, EventArgs e)
        {
        }

        protected void btnSendEmail_Click(object sender, EventArgs e)
        {
            Sender mailSender = new Sender();
            mailSender.SendEmail("myfirstemail@gmail.com", "mysecondemail@gmail.com", "Async mail with attachment", "Async mail with attachment body goes here ...", filePath + "TestFile.txt");
            Response.Redirect("Success.aspx", false);
        }
    }
}

Sender.cs

using System;
using System.IO;
using System.Net.Mail;
using System.Text;
using System.Threading.Tasks;

namespace WebApplication1
{
    public class Sender
    {
        public void SendEmail(string toEmail, string logMail, string title, string body, string attachmentPath)
        {
            var result = ActualEmailSend(toEmail, logMail, title, body, attachmentPath);
        }

        public async Task ActualEmailSend(string toEmail, string logMail, string title, string body, string attachmentPath)
        {
            var emailSender1 = SendEmailAsync(toEmail, title, body, attachmentPath);
            var emailSender2 = SendEmailAsync(logMail, "Copy of " + title, body, attachmentPath);

            await Task.WhenAll(emailSender1, emailSender2);

            if (!string.IsNullOrWhiteSpace(attachmentPath) && File.Exists(attachmentPath))
            {
                File.Delete(attachmentPath);
            }
        }
        public async Task SendEmailAsync(string toEmail, string title, string body, string attachmentPath)
        {
            try
            {
                // class to hold all values from the section system.net/mailSettings/smtp in app.config
                MailConfiguration smtpSection = new MailConfiguration();
                using (MailMessage mailMsg = new MailMessage("<" + smtpSection.FromAddress + ">", toEmail))
                {
                    mailMsg.IsBodyHtml = true;
                    mailMsg.Subject = title;
                    mailMsg.SubjectEncoding = Encoding.UTF8;
                    mailMsg.Body = body;
                    mailMsg.BodyEncoding = Encoding.UTF8;

                    if (!string.IsNullOrWhiteSpace(attachmentPath) && File.Exists(attachmentPath))
                    {
                        Attachment attachment = new Attachment(attachmentPath);
                        mailMsg.Attachments.Add(attachment);
                    }
                    using (SmtpClient smtpClient = new SmtpClient())
                    {
                        smtpClient.Timeout = 1000000;
                        smtpClient.UseDefaultCredentials = false;
                        await smtpClient.SendMailAsync(mailMsg);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("SendEmail exception: " + ex);
            }
            finally
            {
                Console.WriteLine("SendEmail done");
            }
        }
    }
}

关于c# - 始终使用异步/等待在 ASP.NET Web 窗体中的浏览器中加载页面,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45959443/

相关文章:

c# - 我如何将登录页面设置为我在 C# 中没有主菜单的第一页

c# - 下拉列表中的选定值无效

c# - 通过任务取消窗口关闭。如何检测任务是否同步返回?

c# - 在 asp.net 中使用超链接下载文件时处理异常

javascript - jquery 中可以自动刷新而不使页面闪烁吗?就像在 Facebook 上一样

c# - WebControl 和 IDisposable

javascript - NodeJs AWS-SDK s3.upload 上传函数未按预期抛出错误

rust - 如何在测试中运行并发任务? [复制]

c# - 为特定行禁用 jsgrid 的编辑和删除按钮

c# - 当结果实现 IDisposable 时丢弃异步结果