This is the first time that I am using AsyncController (MVC3) and I am having trouble understanding the asynchronous action. My task is to import moderate amount of data from Excel to SQL Server database, using Entity Framework. I thought this would qualify for an async operation and so I wrote a controller explicitly for that purpose. Here is the controller code with async Action
public class CampDonorImportController : AsyncController
{
public void CampDonorImportAsync(string fileName, int taskId) {
...
HttpContext.Application["Progress" + taskId] = 0;
AsyncManager.OutstandingOperations.Increment();
Task.Factory.StartNew(task => {
//Code to import Excel Data
}, taskId);
}
public ActionResult CampDonorImportCompleted() {
return null;
}
public ActionResult ReportImportProgress(int taskId) {
...
return Json(new { Progress = progress, CarryOn = carryOn, Status = status }, JsonRequestBehavior.AllowGet);
}
I call the Async action (CampDonorImportAsync) using following JQuery code
$.ajax({
url: importDonorUrl,
success: function (data, textStatus, jqXHR) {
//Repeatedly call reportImportProgress
refreshTimerId = window.setInterval(reportImportProgress, reportTaskProgressTime);
},
});
The reportImportProgress javascript function calls the ReportImportProgress() action which displays the current progress of the async action.
$.ajax({
url: reportTaskProgressUrl,
complete: function (jqXHR, textStatus, errorThrown) {
var json = $.parseJSON(jqXHR.responseText);
if (!json.CarryOn) {
endImportInit();
alert(json.Status);
}
},
});
The issue is that the call to the Async method(CampDonorImportAsync) blocks other requests from the same page, for example ReportImportProgress() above. I thought that the call to Async action should return immediately, so that other requests can be made, even if the Async task is still going on. I am not sure why the Async request gets blocked and waits for the task to complete, instead of returning immediately. Any Ideas ?
As I describe on my blog, async
does not change the HTTP protocol. With HTTP, you get one response per request, and that's it.
A reliable solution is somewhat more complex than what you're thinking. You need a reliable queue (e.g., Azure queue) and an independent backend (e.g., Azure worker role) that processes requests from that queue. Then, your MVC controller can just add a request to the queue and return. Your frontend can then poll for completion or be notified via something like SignalR.