2012-02-22 90 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