Simant
Simant

Reputation: 4310

always loading page in browser in ASP.NET Web Form using async/await

I am using ASP.NET Web Form to send two emails and once both emails are sent, I am deleting the file from the system. My code is using async/await and its working fine in the Console application but when I moved the same code to the asp.net web form, it's sending emails but I am not getting any response after Task.WaitAll(emailSender1, emailSender2), as a result, the file is not deleted and the browser is always seeing loading. I tried to fix the issue but unable at the end. I need someones help to resolve the issue or any alternate ways that could be accomplished. My code is as below:

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 Code behind

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("[email protected]", "[email protected]", "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 + "]";
        }
    }

Upvotes: 2

Views: 933

Answers (1)

Simant
Simant

Reputation: 4310

After going through this article I came to know that the Console application uses a thread pool SynchronizationContext while GUI or ASP.NET use a one-chunk-at-a-time SynchronizationContext. It means the major cause of deadlock was because of Task.WaitAll(emailSender1, emailSender2). According to the article, I changed this line of code to await Task.WhenAll(emailSender1, emailSender2). The corrected solution is:

Default.aspx.cs code behind

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("[email protected]", "[email protected]", "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");
            }
        }
    }
}

Upvotes: 1

Related Questions