2012-02-22 72 views
2

我有一個webform,我使用TPL在後臺發送電子郵件,因爲我們的SMTP服務器速度很慢,許多用戶最終都無法擺脫提交按鈕。在過去,我曾使用過System.Threading和靜態方法來完成,這是一個類似任務 - 在.NET3.5,我的代碼是這樣的:關於在ASP.NET 4.0中使用任務並行庫的說明

Thread t = new Thread(new ParameterizedThreadStart(SendEmail)); 
t.Start(txtEmail.Text); 

凡SendEmail的簽名是public static void AddEmailToMailingListInBackground(object EmailString)和我所記得的方法必須是靜態的,並且我必須將TextBox txtEmail的值傳遞給異步方法,否則可能會失去對控件值的訪問權限,因爲頁面生命週期是獨立進行的。

現在使用System.Threading.Tasks當我的代碼如下所示:

Task.Factory.StartNew(() => SendEmail(), TaskCreationOptions.LongRunning); 

和SendEmail的簽名是private void SendEmail()和我直接內的方法來訪問的txtEmailText財產。

我在這裏看到兩個主要區別。首先,我的異步方法不再必須是靜態的。其次,如果我使用線程,那麼在頁面的生命週期完成之後很長時間內,我就可以訪問該方法中頁面的控件值。這兩點讓我相信,在所有任務完成或頁面生命週期完成之前,頁面一直保持活動狀態,以先到者爲準。我已經通過調試並通過異步方法進行了測試 - 響應被髮送到瀏覽器,但我仍然能夠瀏覽並訪問控件及其值。 This MSDN article有一點幫助,但仍然沒有真正鞏固我對TPL與執行異步調用之前的.NET4方式發生的事情的理解。

任何人都可以告訴我,如果我的思想是正確的,這是在使用TPL和ASP.NET時的可靠行爲?
有人會關心進一步闡述嗎?

回答

3

它在技術上是而不是可以安全地從ASP.NET線程訪問ASP.NET對象。你會更好地從頁面/請求中提取SendMail所需的細節,並通過閉包傳遞它們。

此外,您需要確保您「觀察」可能在SendMail中發生的任何異常,否則TPL將引發異常,從而導致整個Web應用程序崩潰。你可以用SendMail調用本身的try/catch來做到這一點,或者使用TaskContinuationOptions.OnlyOnFaulted選項來鏈接另一個繼續。在繼續方法中,你只需要訪問前件的Exception屬性,大概是記錄它,以便TPL知道你已經「觀察」了異常。

所以把所有這些組合起來,可能是這樣的:

string userEmail = userEmailTextBox.Text; 
// whatever else SendMail might need from the page/request 

Task.Factory.StartNew(() => SendMail(userEmail)) 
      .ContinueWith(sendEmailAntecedent => 
          { 
           Trace.TraceError(sendEmailAntecedent.Exception.ToString()); 
          }, 
          TaskContinuationOptions.OnlyOnFaulted|TaskContinuationOptions.ExecuteSynchronously); 
+0

感謝德魯,特別是關於異常處理的警告。一些要求澄清。 1)在將try/catch塊中的SendMail調用封裝到SendMail中的行爲與try/catch塊中的SendMail的主體封裝相比,在使用OnlyOnFaulted選項的延續方面有什麼區別?我做了一些閱讀,發現當捕獲方法外部時,你應該尋找一個AggregateException [我認爲] – joelmdev 2012-02-23 14:49:18

+1

@ jm2是的,那是真的。直接在SendMail任務中直接使用try/catch就可以直接使用同步代碼,所以異常將像vanilla .NET代碼一樣傳播。如果您使用ContinuationApproach,則執行SendMail任務時發生的任何異常都將由AggregateException包裝。如果你知道你的SendMail在下面是完全同步的,那麼如果你需要檢查它並對不同類型作出反應,你可以輕鬆/安全地從AggregateException :: InnerException屬性中取出原始異常。 – 2012-02-23 16:46:40

+0

由於評論被破壞,部分內容部分2)您是否說直接訪問值是不安全的,因爲它們可能會發生變化?控制和它們的值是可用的我假設由於SynchronizationContext維護/恢復頁面狀態。 – joelmdev 2012-02-23 18:41:59