Reputation: 489
I have a simple yet time consuming operation: when the user clicks a button, it performs a database intensive operation, processing records from an import table into multiple other tables, one import record at a time. I have a View with a button that triggers the operation and at the end of the operation a report is displayed.
I am looking at ways to notify the user that the operation is being processed.Here is a solution that I liked.
I have been reading up online about Asynchronous operations in MVC. I have found a numbers of links saying that if your process is CPU bound stick to using synchronous operations. Is database related process considered CPU bound or not?
Also if I got the Asynchronous operation route should I use AsyncController as described here or just use Task as in the example I mentioned and also here . or are they all the same?
Upvotes: 5
Views: 5924
Reputation: 456457
The first thing you need to know is that async
doesn't change the HTTP protocol. As I describe on my blog, the HTTP protocol gives you one response for each request. So you can't return once saying it's "in progress" and return again later saying it's "completed".
The easy solution is to only return when it's completed, and just use AJAX to toss up some "in progress..." notification on the client side, updating the page when the request completes. If you want to get more complex, you can use something like SignalR to have the server notify the client when the request is completed.
In particular, an async
MVC action does not return "early"; ASP.NET will wait until all the asynchronous actions are complete, and then send the response. async
code on the server side is all about scalability, not responsiveness.
That said, I do usually recommend asynchronous code on the server side. The one exception is if you only have a single DB backend (discussed well in this blog post). If your backend is a DB cluster or a distributed/NoSQL/SQL Azure DB, then you should consider making it asynchronous.
If you do decide to make your servers asynchronous, just return Task
s; AsyncController
is just around for backwards compatibility these days.
Upvotes: 3
Reputation: 108481
Assuming C# 5.0, I would do something like this following:
// A method to get your intensive dataset
public async Task<IntensiveDataSet> GetIntensiveDataSet() {
//in here you'll want to use any of the newer await Async calls you find
// available for your operations. This prevents thread blocking.
var intensiveDataSet = new IntensiveData();
using (var sqlCommand = new SqlCommand(SqlStatement, sqlConnection))
{
using (var sqlDataReader = await sqlCommand.ExecuteReaderAsync())
{
while (await sqlDataReader.ReadAsync())
{
//build out your intensive data set.
}
}
}
return intensiveDataSet;
}
// Then in your controller, some method that uses that:
public async Task<JsonResult> Intense() {
return Json(await GetIntensiveDataSet());
}
In your JS you'd call it like this (With JQuery):
$.get('/ControllerName/Intense').success(function(data) {
console.log(data);
});
Honestly, I'd just show some sort of spinner while it was running.
If you do need some sort of feedback to the user, you would have to sprinkle updates to your user's Session throughout your async calls... and in order to do that you'd need to pass a reference to that Session around. Then you'd just add another simple JsonResult action that checked the message in the Session variable and poll it with JQuery on an interval. Seems like overkill though. In most cases a simple "This may take a while" is enough for people.
Upvotes: 3
Reputation: 6144
You should consider the option of implementing asynchronization using AJAX. You could handle the client "... processing" message right in your View, with minimum hassle,
$.ajax({
url: @Url.Action("ActionName"),
data: data
}).done(function(data) {
alert('Operation Complete!');
});
alert('Operation Started');
// Display processing animation
Handling async calls on the server side can be expensive, complicated and unnecessary.
Upvotes: 0