views:

1773

answers:

1

I am writing some Utility code to send off emails Async.

var mailClient = new SmtpClient(smtpHost);
mailClient.SendCompleted += new SendCompletedEventHandler(mailClient_SendCompleted);

using (var mailMessage = new MailMessage())
{
    if (!((System.Web.UI.Page)HttpContext.Current.CurrentHandler).IsAsync)
    {
        // set to Async????
    }
    mailClient.SendAsync(mailMessage, new { EmailID });
}

But I get errors because my Pages don't have Async="true" in the page directives.

here is the standard error that you get:

"Asynchronous operations are not allowed in this context. Page starting an
asynchronous operation has to have the Async attribute set to true and an
asynchronous operation can only be started on a page prior to
PreRenderComplete event."

I read this: (last paragraph )

http://msdn.microsoft.com/en-us/magazine/cc163725.aspx

A final point to keep in mind as you build asynchronous pages is that you should not launch asynchronous operations that borrow from the same thread pool that ASP.NET uses. For example, calling ThreadPool.QueueUserWorkItem at a page's asynchronous point is counterproductive because that method draws from the thread pool, resulting in a net gain of zero threads for processing requests. By contrast, calling asynchronous methods built into the Framework, methods such as HttpWebRequest.BeginGetResponse and SqlCommand.BeginExecuteReader, is generally considered to be safe because those methods tend to use completion ports to implement asynchronous behavior.

Questions:

1) How can I update the page to be Async in my c# code?

2) If I can't what is the down side with forcing all my pages to be Async=true?

3) Is there an even better way to thread my task without being "counterproductive"?

+1  A: 

How many different pages do you need to send mail from?

Also, what error did you get when you tried to send async? Please edit your question to contain the entire exception.

Consider creating a single (async) page to send email from. You can call that page by using Server.Transfer, and have it redirect back to your desired page when done.

Finally, if you're sending so many emails that you lose performance when sending mail synchronously, then perhaps you should create a Windows Service to send the actual email. Your ASP.NET page would queue a request to this service (through MSMQ, or WCF) to have the service send the email.

John Saunders
The reason I want to make the call Async is the connection time from the web server to the mail server might/is be slow... I am not sending thousands of emails...
BigBlondeViking
Then you should not be doing it this way. Have a server do the work, opening the connection once, then sending emails forever.
John Saunders
I am send emails from many pages, that's why I am putting the functionality into a Utility class. I also don't have access to the mail server so deploying a wcf app on it wont fly.( would be fun though )
BigBlondeViking
No, you would not need to deploy the WCF app to the mail server. You would deploy it to the same server currently running your web application.
John Saunders
Might be over complicating the issue... I was hoping for a simple way of dealing with this... not by adding another application, I wouldn't get approval to spend time on that anyways.
BigBlondeViking
Ok, though next step would be to make "smtpClient" a static member of your utility class. If, as you say, the issue is the overhead of connection, then maybe that will help if you don't recreate the SmtpClient on every page?
John Saunders
Also, I already told you one way that would be simple: create a single async page. Have your utility class call that page via Server.Transfer (or, at worse, via a redirect). Have that page do the send. When it's done, have it redirect back to the original page.
John Saunders