为使用 ASP.NET MVC 2 AsyncController 实现的长时间运行任务实现进度栏

发布于 2024-10-04 23:34:51 字数 402 浏览 8 评论 0原文

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

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

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

最好的方法是什么?

谢谢,

阿德里安

After reading the documentation on AsyncControllers in ASP.NET MVC 2, I am wondering what's the best way to implement an ajax progress bar in this scenario. It seems a bit odd that the tutorial does not cover this at all.

I guess implementing an AJAX progress bar involves requires additional action method that returns the status of the current task. However, I am not sure about the best way to exchange information on the status of the task between worker threads and that action method.

My best idea so far was to put information on the curent progress into the Session dictionary along with a unique id, and share that id with the client so that it can poll the status. But perhaps there is a much easier way that I did not notice.

What's the best way to do this?

Thanks,

Adrian

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

倚栏听风 2024-10-11 23:34:51

非常有趣的问题!实际上这似乎不是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?Cache?
    会议?);
  • 是否真的需要手动释放资源以及何时应该做什么
    客户端停止监视操作
    (用户关闭浏览器)等。

祝你好运!

Very interesting question! Actually it seems that it is not a task for AsyncController. Async controllers are designed for long-running single-HTTP-query operations at server-side. When you are using async action, this could only help you to release ASP.Net worker thread during some long-running operation(s) and allow it to serve other requests while operation is performed. But from client-side point of view it doesn't matter, is this async controller or not. For client this is just single HTTP request.

You need to redesign this using some long-running queries service in your application. Here is example of controller, that could serve such workflow:

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;
    }
}

And here are client-side code, that could interact with this controller:

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
}

This is very basic concept, there are some missed items here, but I hope you will get the main idea. Also it's up to you how to design components of this system, for example:

  • use singleton for OperationsService,
    or not;
  • where and how long operation result should be stored (DB? Cache?
    Session?);
  • is it really required to manually release resources and what to do when
    client stopped to monitor operation
    (user closed browser) etc.

Best luck!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文