asp.net v4中的循环异步任务

时间:2014-01-21 11:01:25

标签: c# asp.net asynchronous async-await

我使用的是asp.net v4 c#,我有一个电子邮件地址列表。我希望我的一位管理员能够输入一条消息,按" SEND"并且电子邮件一个接一个地出去。

我认为最好的方法是在.net中使用异步方法?单击发送按钮,我获取电子邮件地址列表,然后调用异步方法。我只是不知道如何让它逐个循环遍历列表并发送电子邮件。

需要一次一个地完成,以便我可以保存针对该用户帐户发送的电子邮件的副本。

这是我到目前为止所做的事情(从这里的教程/帖子拼凑而成)

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("test1@test.com");
    emails.Add("test2@test.com");
    emails.Add("test3@test.com");
    emails.Add("test4@test.com");
    emails.Add("test5@test.com");
    emails.Add("test6@test.com");
    emails.Add("test7@test.com");

    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!";
    }
}

我基本上需要将异步函数的调用放入循环中,我将浏览电子邮件地址列表。

这种方法有意义吗?

1 个答案:

答案 0 :(得分:2)

我认为你无法使用ASP.NET 4.5和async/await,这可能是这种情况的理想解决方案(有关详细信息,请参阅thisthis)。

但是,使用ASP 4.0,您仍然可以使用PageAsyncTaskPage.RegisterAsyncTask在您的网页上使用异步代码。这将延长请求的生命周期,直到异步任务完成:

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

然后从worker.BeginInvoke/EndInvoke调用OnBegin/OnEnd。 MSDN有complete sample code

要解决问题本身:

  

这种方法有意义吗?谢谢你的任何信息。

我觉得这没有道理,如果我理解你的代码是正确的。

显然,你在这里做的是启动一个后台线程并在这个线程上进行一些同步操作,比如Thread.Sleep(1000)中的DoSend()。这对于客户端UI应用程序是有意义的(以保持UI响应)。

但是,对于您的服务器端应用程序,您没有任何优势:在您正在进行的操作期间,至少有一个线程(以BeginInvoke开头的线程)仍然被阻止。

您也可以直接在处理HTTP请求的原始线程(DoSend()内)上调用btnSend_Click,而不是BeginInvoke。在这种情况下,您的应用甚至可能会稍微改进一下,因为它的线程切换较少。

现在,您可以重新考虑代码,以使用不需要专用线程的纯异步IO /网络绑定API。这将使您的应用程序扩展得更好。阅读Stephen ClearyThere Is No Thread博客文章,以便更好地了解我所谈论的内容。