Matt Facer
Matt Facer

Reputation: 3105

async task inside loop in asp.net v4

I am using asp.net v4 c# and I have a list of email addresses. I want one of my admins to be able to type a message, press "SEND" and for the emails to go out one by one.

The best way I think is to make use of the async methods in .net? OnClick of the send button, I take the list of email addresses then call the async method. I just don't know how to get it to loop through the list one by one and fire off the email.

Is needs to be done one at a time so that I can save a copy of the email sent against that user's account.

Here's what I have so far (cobbled together from tutorials / posts on here)

protected void btnSend_Click(object sender, EventArgs e)
{
    //get a list of email addresses and send to them
    //these will come from the database once testing comp
    List<string> emails = new List<string>();
    emails.Add("[email protected]");
    emails.Add("[email protected]");
    emails.Add("[email protected]");
    emails.Add("[email protected]");
    emails.Add("[email protected]");
    emails.Add("[email protected]");
    emails.Add("[email protected]");

    SendingDelegate worker = new SendingDelegate(DoSend);
    AsyncCallback completedCallback = new AsyncCallback(DoSendCompletedCallBack);

    lblThreadDetails.Text = "sending to " + emails.Count.ToString() + " email addresses";

    worker.BeginInvoke(completedCallback, AsyncOperationManager.CreateOperation(null));
    sending = true;

}

//boolean flag which indicates whether the async task is running
private bool sending = false;

private delegate bool SendingDelegate();

private bool DoSend()
{
    //send messages
    //emails sent here and saved in the DB each time

    //give the user some feed back on screen. X should be the email address.
    lblThreadDetails.Text = "processing " + x.ToString();
    Thread.Sleep(1000);
    return false;
}

private void DoSendCompletedCallBack(IAsyncResult ar)
{
    //get the original worker delegate and the AsyncOperation instance
    SendingDelegate worker = (SendingDelegate)((AsyncResult)ar).AsyncDelegate;

    //finish the asynchronous operation
    bool success = worker.EndInvoke(ar);
    sending = false;

    if (success)
    {
        //perform sql tasks now that crawl has completed
        lblThreadDetails.Text = "all done!";
    }
}

I basically need to put the calling of the async function in to a loop where I go through the list of email addresses.

Does this approach make sense?

Upvotes: 2

Views: 836

Answers (1)

noseratio
noseratio

Reputation: 61736

I presume you're unable to use use ASP.NET 4.5 and async/await, which might be an ideal solution to this case (see this and this for more info).

However, with ASP 4.0 you still can use asynchronous code on your page with PageAsyncTask and Page.RegisterAsyncTask. That would extend the life time of the request, until the async task has completed:

PageAsyncTask asyncTask = new PageAsyncTask(
    slowTask.OnBegin, slowTask.OnEnd, slowTask1.OnTimeout, 
    "AsyncTaskName", true);

Then you invoke worker.BeginInvoke/EndInvoke from OnBegin/OnEnd. MSDN has a complete sample code of this.

To address the question itself:

Does this approach make sense? thank you for any information.

I don't think it makes sense, if I understood your code correctly.

Apparently, what you're doing here is starting a background thread and doing some synchronous operation on this thread, like Thread.Sleep(1000) inside your DoSend(). That would make sense for a client side UI app (to keep the UI responsive).

However, for your server-side app, you're not getting any advantage: at least one thread (the one started with BeginInvoke) remains blocked during your ongoing operation.

You might as well call DoSend() directly on the original thread that handles the HTTP request (inside btnSend_Click), without BeginInvoke. In that case, your app might even be scaling slightly better, because it'd have less thread switching.

Now, perhaps you can re-factor your code to use pure asynchronous IO/Network-bound APIs which do not require a dedicated thread. That's what would make your app scale much better. Read Stephen Cleary's There Is No Thread blog post, to get a better picture of what I'm talking about.

Upvotes: 2

Related Questions