【问题标题】:Handling Async Request in ASP.NET MVC在 ASP.NET MVC 中处理异步请求
【发布时间】:2012-03-28 08:53:32
【问题描述】:

我有一个 ASP.NET MVC3 应用程序来处理耗时的过程(从网络复制一个大文件)。我们要做的是:

  1. 用户单击按钮发布表单以触发流程
  2. 应用程序启动一个新线程来开始复制文件
  3. 应用程序显示一条消息,说明文件复制过程已开始
  4. 用户可以在后台处理和完成复制时关闭浏览器。

这个想法是,用户不需要对流程的进度进行任何确认,也不需要在流程完成时收到通知。

我们目前让控制器在 Windows 服务中触发事件,并使用 Windows 服务来完成实际工作。我想知道是否有更好/更清洁的方法来做到这一点?

【问题讨论】:

标签: asp.net asp.net-mvc asp.net-mvc-3 asynchronous


【解决方案1】:

您可以使用System.Threading.Tasks.Task 调用带有Action delegateStartNew 方法。

使用这些工具,您的控制器将如下所示:

[HttpPost]
public ActionResult DoSomethingLongRunning()
{
   if (ModelState.IsValid)
   {
       Task.Factory.StartNew(() => 
                   fileCopier.CopyFile(CopyFileParameter1, CopyFileParameter2));

       return RedirectToAction("View Indicating Long Running Progress");
   }
   else
   {
        // there is something wrong with the Post, handle it
        return View("Post fallback view");
   }
}

另一种选择是您可以使用System.Reactive.ConcurrencyIScheduler 接口和TaskPoolScheduler 作为执行操作的具体实现(可能注入到控制器构造函数中。

public ActionResult DoSomethingLongRunning()
{
   if (ModelState.IsValid)
   {
       ISchedulerImplementation.Schedule(new Action(() =>
        {
            fileCopier.CopyFile(CopyFileParameter1, CopyFileParameter2);
        }));
        return RedirectToAction("View Indicating Long Running Progress");
   }
   else
   {
        // there is something wrong with the Post, handle it
        return View("Post fallback view");
   }
}

作为一个好处,如果你这样做,你可以在单元测试时使用TestScheduler作为接口的实现。

【讨论】:

  • 这可能是一种替代方案,但在这种情况下它不是最好的解决方案。因为不需要通知用户触发过程的完成,这可以在 Windows 服务中完全隔离,确保即使 Web 服务器出现故障,它也能正常工作。
【解决方案2】:

我认为让 Windows 服务托管您的长时间运行的进程是最好的选择。如果它由 IIS 托管,则您总是冒着运行它的应用程序池因不活动而被杀死的风险。

一种相关的可能性是在您的 Windows 服务中托管 WCF 服务,并为该服务提供外部 HTTP 或其他端点。这样,您的 Web 界面可以调用 WCF 服务的“启动”契约方法,如果需要,还可以调用其他方法。

【讨论】:

  • 良好的响应,在 IIS 下托管所有内容(即使在不同的应用程序池下)创建并不会隔离您的进程,也不会使其独立。如果 IIS 停止,一切都会停止。还可以查看此链接,了解在 IIS 下托管或在 Windows 服务上托管之间的区别:social.msdn.microsoft.com/Forums/en/wcf/thread/…
【解决方案3】:

我将向 IIS 7 WAS 中托管的 WCF MSMQ 服务发布请求。有an awesome article如何设置。

使用外部资源的长时间运行任务具有很高的失败风险。开发人员经常犯的最大错误是假设硬件和网络具有无限容量并且非常可靠。通常不是。

如果长时间运行的进程因暂时失去网络连接或远程服务器重新启动而中断,则可能会出现问题,甚至是灾难性的。如果您的长时间运行的过程包括额外的处理,例如解压缩文件或分析它,如果没有足够的内存来执行处理,您可能会面临进一步的失败风险。用户可能会提交太多请求,并且没有足够的资源来处理并发问题。如果您让您的 ASP.NET MVC 应用程序通过async controllers 进行处理,那么当您长时间运行的进程在 IIS 回收工作进程时被中断时,您可能会感到惊讶。

MSMQ 4 在减轻这些风险方面做得相当好。如果该过程失败,您可以在放弃之前重试几次。您可以了解如何设置 here。您可以使用application specific deadletter queues 来处理经过多次可接受的尝试后进程失败的情况。这对于操作人员诊断问题很重要。您还可以使用此方案通过电子邮件通知用户该过程失败(或成功),即使发出请求的计算机已关闭。

将其托管在 IIS 而不是 Windows 服务中提供了额外的功能。例如,如果 IIS 工作进程死锁或超过内存阈值,则可以回收它。当您使用一些本机代码执行处理时,后者可能是一个问题。您可以每四个(选择您的时间范围)小时回收一次。后者在处理大块托管内存时相当重要,因为随着时间的推移,大对象头会变得如此多,以至于几乎不可能为另一个大请求分配足够的内存。您可能会发现托管在 Windows 服务中的 WCF 服务可能会遇到此问题。

实际上,这取决于您希望该后台进程有多可靠。如果没有,使用 WCF、MSMQ 和 IIS 可能只是矫枉过正。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-13
    • 1970-01-01
    • 1970-01-01
    • 2012-05-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多