使用ASP实现长期运行任务的进度条。净MVC 2 AsyncController

时间:2022-09-03 20:03:46

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.

在阅读了关于ASP中的异步控制器的文档之后。NET MVC 2,我想知道在这个场景中实现ajax进度条的最佳方式是什么。这似乎有点奇怪,教程根本没有涵盖这一点。

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.

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

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.

到目前为止,我的最佳想法是将有关curent进展的信息连同唯一id一起放入会话字典,并与客户机共享该id,以便它能够轮询状态。但也许有一种更简单的方法我没有注意到。

What's the best way to do this?

最好的方法是什么?

Thanks,

谢谢,

Adrian

艾德里安

1 个解决方案

#1


16  

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.

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

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?);
  • 操作结果应该存储在何处和多长时间(DB?缓存吗?会话?);
  • is it really required to manually release resources and what to do when client stopped to monitor operation (user closed browser) etc.
  • 真的需要手动释放资源吗?当客户端停止监视操作(用户关闭浏览器)时该怎么做?

Best luck!

最好的运气!

#1


16  

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.

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

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?);
  • 操作结果应该存储在何处和多长时间(DB?缓存吗?会话?);
  • is it really required to manually release resources and what to do when client stopped to monitor operation (user closed browser) etc.
  • 真的需要手动释放资源吗?当客户端停止监视操作(用户关闭浏览器)时该怎么做?

Best luck!

最好的运气!