2010-05-28 33 views
40

我一直试图在我的项目中创建一个控制器,以实现相当复杂的报表。因此,他们可能需要相当长的时间,进度条肯定会帮助用户知道事情正在进行。该报告将通过AJAX请求启动,其想法是定期的JSON请求将获得状态并更新进度栏。需要一个带有用户反馈的ASP.NET MVC长时间运行过程

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

感谢您接受所有建议!

+0

报告的输出是什么(screen,pdf?) – 2010-05-28 07:36:23

+0

屏幕 - 无论是HTML还是JSON对象,对我而言都不重要(只要我得到回应,我就可以解析和显示)。 – Jason 2010-05-28 09:31:34

+1

这不是ASP.Net SignalR的绝佳选择吗?我知道这是一条古老的线索,但现在我处于类似的情况。 – 2013-04-09 06:21:34

回答

43

这里有一个示例中,我写道,你可以尝试:

控制器:

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> 

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

+0

感谢Darin,我尝试了你的代码,但仍然让所有的请求都'相互支持'。在今天早上花了很长时间寻找答案之后,我现在开始认为这可能与Session不相关,不允许同时发出多个请求,从而强制请求同步。 我不得不做的一个改变是你使用Task.Factory,因为我目前在.NET 3中工作,而不是4.你认为Task.Factory会解决会话锁定问题吗? – Jason 2010-05-28 11:13:53

+1

此外,我刚刚得到您的代码运行,并通过删除我的控制器中引用会话的任何代码,所以这显然是我的问题。不幸的是,我的控制器都需要我在Session中持有的各种数据(并且在一个BaseController中检索,他们都在扩展),所以我看不到任何简单的解决方法。 – Jason 2010-05-28 11:18:59

+0

会话在异步操作中并不总是可用。 – 2010-05-28 11:32:09

2

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

首先,我们像往常一样设置SignalR连接(请参阅,例如here),但我们的Hub上不需要任何服务器端方法。然后,我们对我们的端点/控制器/无论什么进行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){...}; 

更多细节在我的博客文章here

+5

当然,在上面的问题上,大约2年前发布了有关SignalR的评论。你真的不应该只是发布一个链接到你的博客,因为这是边缘垃圾和只有链接的答案是皱眉。 – 2015-01-15 05:46:03

+0

抱歉,不代表垃圾邮件。答案已更新。 – ulu 2015-01-20 07:32:13

+0

这似乎是一个很好的答案。是否有人使用SignalR而不是像Darrin的答案那样进行轮询? – Jess 2017-07-24 14:32:16

0

如果你有你的Web服务器计算机的访问作为一个选择,你可以创建Windows服务或简单的控制台应用程序执行LON g运行工作。您的Web应用程序应该向db添加一条记录以指示操作应该开始,并且定期检查db中新记录的Windows服务应该开始执行任务并向db报告进度。 您的网络应用程序可以使用ajax请求来检查进度并向用户显示。

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

相关问题