【问题标题】:Clarification on using Task Parallel Library with ASP.NET 4.0关于在 ASP.NET 4.0 中使用任务并行库的说明
【发布时间】:2012-02-23 10:36:37
【问题描述】:

我有一个网络表单,我在其中使用 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(),我直接在该方法中访问txtEmailText 属性。

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

谁能告诉我我的想法是否正确并且在将 TPL 与 ASP.NET 一起使用时这是可靠的行为吗?
有人愿意详细说明吗?

【问题讨论】:

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


    【解决方案1】:

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

    【讨论】:

    • 感谢 Drew,特别是关于异常处理的警告。一些澄清请求。 1)将 SendMail 的调用包装在 try/catch 块中与将 SendMail 的主体包装在 try/catch 块中与使用 OnlyOnFaulted 选项的延续在行为上有什么不同吗?我做了一点阅读,发现在方法之外捕获时,您应该寻找 AggregateException [我认为]
    • @jm2 是的,这是真的。在 SendMail 任务本身中直接使用 try/catch,它只是直接的同步代码,因此异常将像普通的 .NET 代码一样传播。如果您使用 ContinuationApproach,则在执行 SendMail 任务时发生的任何异常都将被 AggregateException 包装。如果您知道您的 SendMail 在下面是完全同步的,那么您可以轻松/安全地从 AggregateException::InnerException 属性中提取原始异常,如果您需要检查它并对不同类型做出反应。
    • 简洁部分,因为 cmets 已损坏 2)您是说直接访问这些值是不安全的,因为它们可能会发生变化?由于 SynchronizationContext 维护/恢复页面状态,我假设控件及其值可用。
    • 在 ASP.NET 同步上下文之外访问与 ASP.NET 相关的任何内容可能会导致错误,因为基础 HttpContext 实例可能不存在。如果您使用显式 TaskScheduler.FromCurrentSyncrhonizationContext() 线程将在由 AspNetSynchronizationContext 类配置的线程上调用,该类可以安全地访问该内容,但请记住,此时您可能会保留大量的包袱。这就是为什么我只建议在安排工作时将 SendMail 所需的值从当前请求中提升出来。
    猜你喜欢
    • 2013-04-20
    • 1970-01-01
    • 1970-01-01
    • 2017-08-29
    • 1970-01-01
    • 1970-01-01
    • 2021-09-23
    • 2013-09-14
    • 1970-01-01
    相关资源
    最近更新 更多