2012-03-28 141 views
6

我有一个ASP.NET MVC3应用程序处理耗时的进程(从网络复制大文件)。我们想要做的是:处理ASP.NET MVC中的异步请求

  1. 用户点击一个按钮来发布形式触发过程
  2. 应用程序启动一个新线程开始复制文件
  3. 应用程序显示一个消息,说该文件复制进程已经开始
  4. 用户可以在复制处理完毕并关闭浏览器的同时在后台完成。

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

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

+3

对于MVC 3,看我的MSDN文章:http://msdn.microsoft.com/en-us/library/ee728598(VS.98).aspx如果你可以使用MVC 4和Developer Express公司11,我编写一个简单得多的新的Async/MVC教程。 – RickAndMSFT 2012-03-28 17:34:53

回答

6

您可以使用System.Threading.Tasks.Task调用StartNew方法与Action delegate

使用这些工具,你的控制器会是这个样子:

[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当你在单元测试接口的实现。

+0

这可能是一种选择,但在这种情况下它不是最好的解决方案。由于用户不需要通知触发进程的完成情况,因此即使Web服务器出现故障,也可以在Windows服务中完全隔离,以确保其可以正常工作。 – 2012-03-28 09:32:55

3

我认为拥有Windows服务主机您的长期运行过程是最好的选择。如果它是由IIS托管的,那么您总是冒着应用程序池的运行时间处于不活动状态而死亡的风险。

一种相关的可能性是在Windows服务中托管WCF服务,并为服务提供外部HTTP或其他端点。这样,您的Web界面就可以调用WCF服务的“开始”合同方法,并且可能需要其他方法。

+0

良好的响应,在IIS下托管所有东西(甚至在不同的应用程序池下)创建并不会隔离您的进程,也不会使其独立。如果IIS停止,一切都会停止。另请参阅此链接,了解IIS与Windows服务之间的区别:http://social.msdn.microsoft.com/Forums/en/wcf/thread/015d711d-ce5a-46a1-a93e-1c68746e76d3 – 2012-03-28 09:28:48

2

我将向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可能只是矫枉过正。