【问题标题】:Implementing a Progress bar for long running task implemented with an ASP.NET MVC 2 AsyncController为使用 ASP.NET MVC 2 AsyncController 实现的长时间运行的任务实现进度条
【发布时间】:2011-05-18 08:27:30
【问题描述】:

在阅读了 ASP.NET MVC 2 中的documentation on AsyncControllers 之后,我想知道在这种情况下实现 ajax 进度条的最佳方法是什么。本教程根本没有涵盖这一点,这似乎有点奇怪。

我猜想实现 AJAX 进度条需要额外的操作方法来返回当前任务的状态。但是,我不确定在工作线程和该操作方法之间交换有关任务状态的信息的最佳方式。

到目前为止,我最好的想法是将有关当前进度的信息与唯一 ID 一起放入 Session 字典中,并与客户端共享该 ID,以便它可以轮询状态。但也许还有一种我没有注意到的更简单的方法。

最好的方法是什么?

谢谢,

阿德里安

【问题讨论】:

  • 这有点像问为什么您没有获得正常请求的进度条。当你这样想的时候应该回答自己。
  • @nick:不是真的。正常请求不会长时间运行。对于最多需要几秒钟的事情,没有人需要进度条。但是,如果您使用的是异步控制器,您预计请求会花费很长时间。这就是您需要进度条的时候。只有我觉得这很明显吗?
  • 使用异步控制器意味着任务转移到其他地方-因此您将其设为异步并且可以允许其余代码继续执行-不需要任何长时间-运行任务。只是意味着您可以提高性能。通过网络请求 - 客户会注意到任何好处。你是唯一一个吗?这说明什么?你在期待什么?服务器不断发送多个响应,以便您获得一个进度条 - 这将抵消您的性能优势并添加非常愚蠢的行为。

标签: asp.net-mvc ajax asp.net-mvc-2 asynccontroller


【解决方案1】:

非常有趣的问题!实际上,这似乎不是AsyncController 的任务。异步控制器专为服务器端长时间运行的单 HTTP 查询操作而设计。当您使用异步操作时,这只能帮助您在一些长时间运行的操作期间释放 ASP.Net 工作线程,并允许它在执行操作时服务其他请求。但是从客户端的角度来看,这个异步控制器是否无关紧要。对于客户端,这只是单个 HTTP 请求。

您需要在应用程序中使用一些长时间运行的查询服务来重新设计它。这是控制器的示例,它可以服务于这样的工作流程:

public class LongOperationsController : Controller
{
    public ActionResult StartOperation(OperationData data)
    { 
        Guid operationId = Guid.NewGuid(); // unique identifier for your operation
        OperationsService.DoStartOperation(operationId, data); // service starts to perform operation using separate thread
        return new JsonResult(operationId); // operation id should be sent to client to allow progress monitoring
    }

    public ActionResult GetOperationStatus(Guid operationId) 
    {
        var status = OperationsService.GetStatus(operationId); // this method returns some object, that describes status of operation (e.g. progress, current task etc.)
        return new JsonResult(status); // returning it to client
    }

    public ActionResult GetOperationResult(Guid operationId)
    {
        var result = OperationsService.GetOperationResult(operationId); // this should throw exception if operation is not yet completed
        return new JsonResult(result);
    }

    public ActionResult ClearOperation(Guid operationId)
    {
        OperationsService.ClearOperationResult(operationId); // we should delete operation result if it was handled by client
        return true;
    }
}

这里是客户端代码,可以与这个控制器交互:

var operationId;
function startOperation(data) {
    $.post('/LongOperations/StartOperation', data, function(response) {
        operationId = response; // store operationId
        startOperationMonitoring(); // start
    }, 'json');
}

function startOperationMonitoring() {
    // todo : periodically call updateOperationStatus() to check status at server-side
}

function updateOperationStatus() {
    // todo : get result of GetOperationStatus action from controller 
    // todo : if status is 'running', update progress bar with value from server, if 'completed' - stop operation monitoring and call finishOperation()
}

function finishOperation() {
    // todo : get result of GetOperationResult action from controller and update UI
    // todo : call ClearOperation action from controller to free resources
}

这是一个非常基本的概念,这里有一些遗漏的项目,但我希望你能明白主要的想法。如何设计这个系统的组件也取决于你,例如:

  • 对 OperationsService 使用单例, 或不;
  • 应该将操作结果存储在哪里以及存储多长时间(DB?缓存? 会议?);
  • 真的需要手动释放资源吗? 客户端停止监视操作 (用户关闭浏览器)等

祝你好运!

【讨论】:

  • 嗨梅斯,感谢您的详细回答。这正是我想出的方法,我在我的 OP 的第三段中进行了描述。这工作得很好,但它似乎是一个过于繁琐的实现,应该成为几乎每个异步控制器(即进度条)的一部分。我会认为(或至少希望)ASP.NET MVC 比这更好,并为开箱即用的异步控制器提供某种进度指示器。
  • 我想知道,您还没有完全理解异步控制器的设计目的。它与异步请求处理无关,它与在服务器上运行长时间操作有关。不幸的是,HTTP 是同步协议,从一开始就不是为这样的目的而设计的。
  • 另外,在我看来,将一个请求保持在打开状态并定期轮询服务器使用并行请求的进度并不是一个最佳主意。
  • 时髦的解决方案 - 我会给你 :)
  • 维克多:我完全理解它们的用途。我从未说过异步控制器主要用于显示进度条。我的意思是,如果您使用异步控制器,您可能还需要一个进度条。看起来很明显,我希望 ASP.NET MVC 能够为实现开箱即用的进度条提供一些帮助。同样,我确实了解如何解决这个缺失的功能(解决方案在我的 OP 中!),但我希望有更好的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多