需要一个带有用户反馈的 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 [关闭]

使用不记名令牌授权 ASP.net mvc 操作方法

带有 jQ​​uery 验证的 ASP.Net MVC Ajax 表单

带有 Jquery 模态形式的 asp.net MVC