我正在使用 asp.net v4 c#,并且我有一个电子邮件地址列表。我希望我的一位管理员能够输入消息,按“发送”,然后将电子邮件一封一封地发送出去。
我认为最好的方法是利用.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("<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="73071600074233071600075d101c1e" rel="noreferrer noopener nofollow">[email protected]</a>");
emails.Add("<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="7b0f1e080f493b0f1e080f55181416" rel="noreferrer noopener nofollow">[email protected]</a>");
emails.Add("<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="483c2d3b3c7b083c2d3b3c662b2725" rel="noreferrer noopener nofollow">[email protected]</a>");
emails.Add("<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a9ddccdadd9de9ddccdadd87cac6c4" rel="noreferrer noopener nofollow">[email protected]</a>");
emails.Add("<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fd89988e89c8bd89988e89d39e9290" rel="noreferrer noopener nofollow">[email protected]</a>");
emails.Add("<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="70041503044630041503045e131f1d" rel="noreferrer noopener nofollow">[email protected]</a>");
emails.Add("<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f88c9d8b8ccfb88c9d8b8cd69b9795" rel="noreferrer noopener nofollow">[email protected]</a>");
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!";
}
}
我基本上需要将异步函数的调用放入一个循环中,在其中遍历电子邮件地址列表。
这种方法有意义吗?
最佳答案
我认为您无法使用 ASP.NET 4.5 和 async/await
,这可能是这种情况的理想解决方案(有关详细信息,请参阅 this 和 this)。
但是,使用 ASP 4.0,您仍然可以在页面上使用异步代码 PageAsyncTask
和Page.RegisterAsyncTask
。这将延长请求的生命周期,直到异步任务完成:
PageAsyncTask asyncTask = new PageAsyncTask(
slowTask.OnBegin, slowTask.OnEnd, slowTask1.OnTimeout,
"AsyncTaskName", true);
然后你调用worker.BeginInvoke/EndInvoke
来自OnBegin/OnEnd
。 MSDN 有一个complete sample code的这个。
解决问题本身:
Does this approach make sense? thank you for any information.
如果我正确理解了您的代码,我认为这没有意义。
显然,您在这里所做的是启动一个后台线程并在此线程上执行一些同步操作,例如 Thread.Sleep(1000)
在你的DoSend()
里面。这对于客户端 UI 应用程序来说很有意义(以保持 UI 响应)。
但是,对于您的服务器端应用程序,您没有获得任何优势:在您正在进行的操作期间,至少有一个线程(以 BeginInvoke
开头的线程)保持阻塞。
您不妨调用DoSend()
直接在处理 HTTP 请求的原始线程上(在 btnSend_Click
内),没有 BeginInvoke
。在这种情况下,您的应用甚至可能会稍微更好地扩展,因为它的线程切换更少。
现在,也许您可以重构代码以使用不需要专用线程的纯异步 IO/网络绑定(bind) API。这将使您的应用程序扩展得更好。阅读 Stephen Cleary的There Is No Thread博客文章,以便更好地了解我正在谈论的内容。
关于c# - asp.net v4 中循环内的异步任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21256209/