澄清在ASP.NET 4.0中使用任务并行库

时间:2012-02-22 20:07:23

标签: asp.net asynchronous asp.net-4.0 task-parallel-library

我有一个网络表单,我使用TPL在后台发送电子邮件,因为我们的SMTP服务器很慢,很多用户最终都会因为沮丧而敲响提交按钮。在过去,我曾使用System.Threading和静态方法来完成类似的任务 - 在.NET3.5中,我的代码看起来像这样:

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(),我直接在该方法中访问Text txtEmail属性。

我有两个主要区别看这里。首先,我的异步方法不再是静态的。其次,如果我使用Threads,我可以在Page的生命周期完成后很长时间内访问方法中的Page的控制值。这两点让我相信,在所有任务完成或页面生命周期完成之前,页面一直处于活动状态,以先到者为准。我通过调试和逐步调试异步方法对此进行了测试 - 响应被发送到浏览器但我仍然可以单步执行并访问控件及其值。 This MSDN article有点帮助但仍然没有真正巩固我对TPL与.NET4之前执行异步调用的方式的理解。

任何人都可以告诉我,如果我的想法是正确的,这是在使用TPL与ASP.NET时可靠的行为?
有人愿意进一步阐述吗?

1 个答案:

答案 0 :(得分:3)

从ASP.NET线程访问ASP.NET对象在技术上是安全的。最好不要从页面/请求中提取SendMail需要的详细信息,并通过闭包传递它们。

此外,您需要确保“观察”SendMail中可能发生的任何异常,否则TPL将引发一个异常,从而导致整个Web应用程序崩溃。您可以使用TryMail调用本身的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);