异步控制器(MVC),带有“停止”的长时间运行过程

本文关键字:停止 长时间 过程 运行 带有 控制器 异步控制 MVC 异步 | 更新日期: 2023-09-27 18:13:39

我对运行一个长过程很感兴趣,我想在结果开始进来时立即更新UI,而不是等待它完成。

我该怎么做呢?我读过Async控制器,但他们似乎没有为此目的内置任何东西。

只是保存结果在应用程序/会话对象作为结果进来,并使用轮询从客户端?我可以想到几种可能出错的方法(如用户关闭页面,对象永远留在Application对象中-需要自己管理这些对象的过期,额外的服务器负载轮询等)。

任何想法吗?

谢谢

异步控制器(MVC),带有“停止”的长时间运行过程

我最近正在尝试解决类似的问题(将长时间运行的服务器操作的实时进度报告给客户端),结果发现SignalR非常适合这种情况。

基本上它是一个包装长轮询和Web Sockets的库,(透明地)使用服务器和客户端上可用的任何东西。

到目前为止我对它只有很好的经验。

可以使用ThreadPool运行长时间运行的任务。它可以更新用户可以轮询的应用程序/会话中的状态。正如你所指出的,这有一些终生的问题。除了你指出的,应用程序池可以回收——但也许这没关系。

该操作的逻辑作用域是什么?它是一个系统类型的长时间运行的任务,有人/许多人需要查询进度吗?还是代表特定用户的长时间运行任务?如果是后者,那么如果用户的会话超时,等等,也没关系。如果是前者,那么你需要更耐用。例如,您可以将任务请求、状态和进度存储在数据库中。这样,在应用程序重新启动时,它可以从它离开的地方恢复,并且任何人都可以轻松查询(如果是系统级任务,则是另一个决策点)。

最后要考虑的是你是否会有多个web角色(web farm/cluster)。如果考虑到这一点,那么使用DB甚至单独的worker角色/服务会更合适。

所以这一切都归结为任务的类型,谁需要监视它,以及持久性要求是什么。如果它只是一个用户任务,保持简单,queueuserworkitem和会话状态。

这篇文章似乎描述了你想要的,简单和无信号:

ASP。. NET MVC 3:用于长时间运行任务的异步jQuery进度指示器

控制器:

公共类HomeController: Controller{private static Dictionary任务= new Dictionary();

 public ActionResult Index()
 {
   return View();
 }
 public ActionResult Start()
 {
   var taskId = Guid.NewGuid();
   tasks.Add(taskId, 0);
   Task.Factory.StartNew(() =>
   {
     for (var i = 0; i <= 100; i++)
     {
       tasks[taskId] = i; // update task progress
       Thread.Sleep(50); // simulate long running operation
     }
     tasks.Remove(taskId);
   });
   return Json(taskId);
 }
 public ActionResult Progress(Guid id)
 {
   return Json(tasks.Keys.Contains(id) ? tasks[id] : 100);
 }

}

视图:

<script type="text/javascript">
function updateMonitor(taskId, status) {
  $("#" + taskId).html("Task [" + taskId + "]: " + status);
}
$(function () {
  $("#start").click(function (e) {
   e.preventDefault();
   $.post("Home/Start", {}, function (taskId) {
     // Init monitors
     $("#monitors").append($("<p id='" + taskId + "'/>"));
     updateMonitor(taskId, "Started");
     // Periodically update monitors
     var intervalId = setInterval(function () {
       $.post("Home/Progress", { id: taskId }, function (progress) {
         if (progress >= 100) {
           updateMonitor(taskId, "Completed");
         clearInterval(intervalId);
         } else {
           updateMonitor(taskId, progress + "%");
         }
       });
     }, 100);
   });
 });

});