需要一个带有用户反馈的 ASP.NET MVC 长时间运行的进程
Posted
技术标签:
【中文标题】需要一个带有用户反馈的 ASP.NET MVC 长时间运行的进程【英文标题】:Need an ASP.NET MVC long running process with user feedback 【发布时间】:2011-02-25 00:25:56 【问题描述】:我一直在尝试在我的项目中创建一个控制器,以交付可能非常复杂的报告。因此,他们可能会花费相对较长的时间,而进度条肯定会帮助用户了解事情的进展。该报告将通过 AJAX 请求启动,其想法是定期 JSON 请求将获取状态并更新进度条。
我一直在尝试使用 AsyncController,因为这似乎是一种运行长进程而不占用资源的好方法,但它似乎没有给我任何检查进度的方法(而且似乎进一步阻止JSON 请求,我还没有发现原因)。之后,我尝试将进度存储在控制器上的静态变量中并从中读取状态 - 但老实说,这一切似乎都有点 hacky!
感谢所有建议!
【问题讨论】:
报告的输出是什么(屏幕,pdf?) 屏幕 - 目前对我来说是 html 块还是 JSON 对象并不重要(只要我得到响应,我就可以解析和显示)。 这不是 ASP.Net SignalR 的理想选择吗?我知道这是一个旧线程,但我现在处于类似情况。 所以,我很好奇您最终使用什么来解决您所面临的会话锁定问题。 【参考方案1】:这是我写的一个示例,你可以试试:
控制器:
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);
Index() 视图:
<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 秒)以更新进度。您可以调整参数以适应您的场景。进一步的改进是添加异常处理。
【讨论】:
谢谢达林,我尝试了你的代码,但仍然让所有请求一个接一个地“备份”。在今天早上慢慢地寻找答案后,我现在开始认为这可能与 Session 不允许同时多个请求有关,从而迫使请求是同步的。我必须做出的一项更改是您使用 Task.Factory,因为我目前使用的是 .NET 3,而不是 4。您认为 Task.Factory 会解决 Session 锁定问题吗? 另外,我刚刚让您的代码运行,我通过删除控制器中引用 Session 的任何代码来做到这一点,所以这显然是我的问题。不幸的是,我的控制器都需要我在 Session 中保存的各种数据(并在它们都扩展的 BaseController 中检索),所以我看不到任何简单的方法来解决这个问题。 Session 在异步操作中并不总是可用的。 如果这些操作正在调用服务类,该类是否应该像老式的 Windows 应用程序那样通过“事件”公开其进度? @jalchr,不,您应该在您的服务上实现相同的任务系统,它允许您启动操作,然后有另一个服务方法允许您查询给定任务的进度在服务方面。【参考方案2】:在这个问题得到解答 4.5 年后,我们有一个库可以使这项任务变得更加容易:SignalR。无需使用共享状态(这很糟糕,因为它会导致意外结果),只需使用 HubContext 类连接到向客户端发送消息的 Hub。
首先,我们像往常一样设置 SignalR 连接(参见例如here),但我们不需要在 Hub 上使用任何服务器端方法。然后我们对 Endpoint/Controller/whatever 进行 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
【讨论】:
当然,大约 2 年前在上述问题上发表了关于 SignalR 的评论。你真的不应该只发布一个指向你博客的链接,因为那是垃圾邮件的边缘,而且只有链接的答案是不受欢迎的。 这似乎是一个很好的答案。有没有人使用 SignalR 而不是 Darrin 的回答中的轮询?【参考方案3】:如果您可以选择访问您的 Web 服务器计算机,您可以创建 Windows 服务或简单的控制台应用程序来执行长时间运行的工作。您的 Web 应用程序应该向 db 添加一条记录以指示应该开始操作,并且定期检查 db 中的新记录的 Windows 服务应该开始执行任务并向 db 报告进度。 您的网络应用可以使用 ajax 请求来检查进度并向用户显示。
我使用这种方法为asp.net mvc 应用程序实现了excel 报告。 此报告由 Windows 服务创建,该服务在机器上运行并不断检查报告表中的新记录,当它找到新记录时,它开始创建报告并通过更新记录字段指示进度。 Asp.net mvc 应用程序一直在添加新的报告记录并在数据库中跟踪进度,直到完成,然后提供了一个可供下载的准备文件的链接。
【讨论】:
以上是关于需要一个带有用户反馈的 ASP.NET MVC 长时间运行的进程的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET MVC 获取带有用户 ID 的文件上传名称并应用于单独的字段
带有相对路径的 ASP.Net MVC 和 RenderPartial
ASP .NET 5 MVC 6 Identity 3 Roles Claims Groups [关闭]