需要用户反馈的ASP.NET MVC长时间运行过程

我一直在试图在我的项目中创build一个控制器来实现可能是相当复杂的报告。 因此,他们可能需要相当长的时间,进度条肯定会帮助用户知道事情正在进行。 该报告将通过AJAX请求启动,周期性的JSON请求将获得状态并更新进度条。

我一直在尝试AsyncController,因为这似乎是一个很好的方式来运行长进程而不捆绑资源,但它似乎没有给我任何方式来检查进度(似乎阻止进一步的JSON请求和我还没有发现为什么)。 之后,我尝试着在控制器上的静态variables中存储进度,并从中读取状态 – 但说实话,这似乎有点哈克!

所有的build议感激地接受!

下面是我写的一个示例,你可以尝试:

控制器:

public class HomeController : AsyncController { public ActionResult Index() { return View(); } public void SomeTaskAsync(int id) { AsyncManager.OutstandingOperations.Increment(); Task.Factory.StartNew(taskId => { for (int i = 0; i < 100; i++) { Thread.Sleep(200); HttpContext.Application["task" + taskId] = i; } var result = "result"; AsyncManager.OutstandingOperations.Decrement(); AsyncManager.Parameters["result"] = result; return result; }, id); } public ActionResult SomeTaskCompleted(string result) { return Content(result, "text/plain"); } public ActionResult SomeTaskProgress(int id) { return Json(new { Progress = HttpContext.Application["task" + id] }, JsonRequestBehavior.AllowGet); } } 

视图:

 <script type="text/javascript"> $(function () { var taskId = 543; $.get('/home/sometask', { id: taskId }, function (result) { window.clearInterval(intervalId); $('#result').html(result); }); var intervalId = window.setInterval(function () { $.getJSON('/home/sometaskprogress', { id: taskId }, function (json) { $('#progress').html(json.Progress + '%'); }); }, 5000); }); </script> <div id="progress"></div> <div id="result"></div> 

这个想法是启动一个asynchronous操作,将使用HttpContext.Application报告进度,这意味着每个任务必须有一个唯一的ID。 然后在客户端,我们启动任务,然后发送多个AJAX请求(每5秒)来更新进度。 您可以调整参数以适应您的情况。 进一步的改进是增加exception处理。

在这个问题已经回答了4.5年之后,我们有一个库可以使这个任务变得更容易:SignalR。 不需要使用共享状态(这是不好的,因为它可能导致意外的结果),只需使用HubContext类连接到发送消息到客户端的集线器。

首先,我们像往常一样build立SignalR连接(请参阅此处 ),除了我们的Hub上不需要任何服务器端方法。 然后,我们对我们的terminal/控制器/任何一个进行AJAX调用,并传递连接ID,我们像往常一样: var connectionId = $.connection.hub.id; 。 在服务器端,你可以在不同的线程上启动你的进程,并向客户端返回200 OK。 该过程将知道connectionId,以便它可以将消息发送回客户端,如下所示:

 GlobalHost.ConnectionManager.GetHubContext<LogHub>() .Clients.Client(connectionId) .log(message); 

在这里, log是你想从服务器调用的客户端方法,因此它应该像你通常对SignalR所做的那样定义:

 $.connection.logHub.client.log = function(message){...}; 

更多细节在我的博客文章这里

如果您有权访问Web服务器计算机,则可以创buildWindows服务或简单控制台应用程序来执行长时间运行的工作。 你的Web应用程序应该添加一个logging到数据库,以指示操作应该开始,你的Windows服务定期检查数据库中的新logging应该开始执行任务和报告进度数据库。 您的networking应用程序可以使用Ajax请求来检查进度并显示给用户。

我用这个方法来实现asp.net mvc应用程序的excel报告。 这个报告是由在机器上运行的windows服务创build的,并不断地检查报告表中的新logging,当它发现一个新的logging时,它开始创build一个报告,并通过更新logging字段来指示进度。 Asp.net mvc应用程序刚刚添加了新的报告logging,并在数据库中跟踪进度,直到完成,然后提供一个链接,以准备下载文件。