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.