Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing a Progress bar for long running task implemented with an ASP.NET MVC 2 AsyncController

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

like image 590
Adrian Grigore Avatar asked Dec 01 '10 07:12

Adrian Grigore


People also ask

How can add progress bar in asp net?

"File" - "New Project" - "C#" - "ASP.NET Empty Web Application" (to avoid adding a master page). Provide the web site a name such as "ProgressBAR" or another as you wish and specify the location. Then right-click on Solution Explorer - "Add New Item" - "Default. aspx page".


1 Answers

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!

like image 55
Victor Haydin Avatar answered Sep 19 '22 09:09

Victor Haydin