2014-01-21 54 views
2

我正在使用asp.net v4 c#,並且我有一個電子郵件地址列表。我希望我的一個管理員能夠輸入消息,按「發送」,電子郵件就可以一個接一個地發送出去。asp.net v4循環內的異步任務

我認爲最好的方法是使用.net中的異步方法? OnClick的發送按鈕,我把電子郵件地址列表,然後調用異步方法。我只是不知道如何讓它逐個循環播放列表併發送電子郵件。

需要一次完成一次,以便我可以保存發送給該用戶帳戶的電子郵件副本。

這裏是我到目前爲止(從教程/職位拼湊起來放在這裏)

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

基本上,我需要把異步函數的調用到一個循環,我通過電子郵件列表地址。

這種方法有意義嗎?

+0

切線:你確實知道你不需要'新''委託對象了嗎?至少對我來說,這將使代碼更具可讀性,因爲您不需要追溯到委託變量指向的位置。 – millimoose

+0

I.e.你可以使用'(DoSend as Action).BeginInvoke(DoSendCompletedCallback,AsyncOperationManager.CreateOperation(null))' – millimoose

+1

此外,還有一個明顯的問題不是你的方法,而是你的測試工具,它從後臺操作更新GUI。大多數GUI系統是單線程的,即創建和更新UI必須發生在運行事件循環的線程上。 – millimoose

回答

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); 

然後你從OnBegin/OnEnd調用worker.BeginInvoke/EndInvoke。 MSDN有這個complete sample code

爲了解決這個問題本身:

請問這種做法是否合理?謝謝你的任何信息。

我覺得沒有道理,,如果我正確理解你的代碼。

顯然,你在這裏做的是開始一個後臺線程,並在這個線程上做一些同步操作,如在DoSend()內部的Thread.Sleep(1000)。這對於客戶端UI應用程序來說是有意義的(以保持UI的響應)。

但是,對於您的服務器端應用程序,您沒有任何優勢:至少有一個線程(以BeginInvoke開頭的線程)在正在進行的操作過程中仍然被阻止。

您也可以直接在處理HTTP請求的原始線程(在btnSend_Click之內)調用DoSend(),而不使用BeginInvoke。在這種情況下,您的應用程序甚至可能會稍微好一點,因爲它的線程切換次數會減少。

現在,您可能會重新考慮您的代碼,以使用不需要專用線程的純異步IO /網絡綁定API。這會讓你的應用程序的規模好得多。閱讀Stephen ClearyThere Is No Thread博客文章,以更好地瞭解我正在談論的內容。