Need an ASP.NET MVC long running process with user feedback

Jason picture Jason · May 28, 2010 · Viewed 27.2k times · Source

I've been trying to create a controller in my project for delivering what could turn out to be quite complex reports. As a result they can take a relatively long time and a progress bar would certainly help users to know that things are progressing. The report will be kicked off via an AJAX request, with the idea being that periodic JSON requests will get the status and update the progress bar.

I've been experimenting with the AsyncController as that seems to be a nice way of running long processes without tying up resources, but it doesn't appear to give me any way of checking on the progress (and seems to block further JSON requests and I haven't discovered why yet). After that I've tried resorting to storing progress in a static variable on the controller and reading the status from that - but to be honest that all seems a bit hacky!

All suggestions gratefully accepted!

Answer

Darin Dimitrov picture Darin Dimitrov · May 28, 2010

Here's a sample I wrote that you could try:

Controller:

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() View:

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

The idea is to start an asynchronous operation that will report the progress using HttpContext.Application meaning that each task must have an unique id. Then on the client side we start the task and then send multiple AJAX requests (every 5s) to update the progress. You may tweak the parameters to adjust to your scenario. Further improvement would be to add exception handling.