mvc async await link clicks wait till task finished - asp.net-mvc

I have a MVC website where I am trying to call a method with async. My code is like below:
Views
Submit Download
$(document).on('click', '.submit-download', function (evt) {
var submit_url = '/SubmitDownloads/24589;
$.ajax({
type: 'POST',
url: submit_url,
success: function (data) {
if (data.Item1)
location.reload();
}
});
});
Controller
[HttpPost]
public async Task<JsonResult> SubmitDownloads(int id)
{
var respository = new WorkflowRepository();
var result = await respository.SubmitAsync(id);
return Json(result, JsonRequestBehavior.AllowGet);
}
Repository Method
//db service call which will take much longer time
public async Task<Tuple<bool, string>> SubmitAsync(id)
{
//long running method here
await Task.Delay(20000);
return new Tuple<bool, string>(true, "done with " + id);
}
When user clicks on the 'Submit Download' link in Views, it complete the entire function quickly as its supposed to do and page shows responsive like scrollable, menu shows fine. But when I click on any link in the page, it waits till the entire operation is finished (20 seconds) and then redirect to respective URL.
If I change the Task.Delay to 50 seconds, link click takes 50 seconds to redirect.
Can you please guide me what I am missing here?

But when I click on any link in the page, it waits till the entire operation is finished (20 seconds) and then redirect to respective URL.
Asynchronous controller methods don't make the HTTP interaction async, just the interaction from the web server to the web application async. The idea is that a high volume web server can free up threads to service other requests while long-running requests are doing their thing.
When you click on a link, the browser needs to wait for a response before, well, processing that response (displaying the page). There's no way to display a page without waiting for that page to be sent from the web server.

Related

jQuery axax lifecycle and response in ASP.NET MVC application or API in general

I need a clarification on jQuery Ajax lifecycle when calling an endpoint, in my specific case an ASP.NET MVC (Net core/Net 5) application.
What I specifically need is to know how the success/error event chain works and when exactly the control is returned to jquery once the http call is fired.
Let's imagine a jquery ajax like this
postData = JSON.stringify({test: 1, anotherVariable : "YEEEE"});
$.ajax({
url: '#Url.Action("MyAspNetAction", "MyAspNetController")',
type: "POST",
contentType: 'application/json; charset=utf-8',
dataType: "json",
data: postData,
success: function (result) {
showMessage(result.responseText, result.success ? 'success' : 'error', 3000)
},
error: function (error) {
showMessage(result.responseText, 'success', 3000)
}
});
On the server I have an async Task controller which we could define as:
public async Task<JsonResult> MyAspNetAction([FromBody] MyAspNetActionModel){
try{
await someLongAction();
return some jsonresult { success = true, responseText = "HELLO"}
}
catch(Exception ex)
{
return some jsonresult { success = false, responseText = "ERROR"}
}
}
which gets executed async from asp net (I guess).
Now, Let's suppose I do various risky task in this action, like manipulating
HttpContext.Session["key"]
ViewData["Key"]
calls to other async stuff which takes some time to get executed (let's say 30 seconds for the sake of putting up a worst-case scenario.
All this togheter.
Now,
WHEN javascript gets control back and WHEN SUCCESS???
Am I handling this right?
I mean, all that async stuff is happening (ajax async, mvc action is async and so on.
Will the jquery action go to succes only after my MVC action is completed and gets the result?
Or the mere fact that jquery ajax managed to call my action will result in a HTTP 200 (so it's ok/success) and it will ignore all the code called inside, which has to be handled in another way, and the following javascript will be executed?
Basically I want to know if I can execute all the code in the MVC action being sure that ajax will enter in succes/error only when the action completed all the code
AND
if the javascript following the jquery ajax will continue executing and the control to the ajax action will return later
The client and the server on an HTTP request work independently.
The client issues a request.
The server handles the request and sends the response.
The client receives the response.
Each end can be running on any architecture and, if possible, the client can block during 2 or asynchronously await for 3 during 2.
The server (2) can be synchronous or asynchronous, but it sequentially does:
Receive the request.
Handle the request.
Send the response.
Regarding ASP.NET, you should not be concurrently messing with HTTP-related components or view components.
Your action method should:
Collect data from HTTP (model binding and other data).
Call any model/services needed to handle the request.
Produce the response (View, or any other response type).

ASP MVC RedirectToAction Until Async Process Finishes

I have a Action method in my controller that continues to redirect back to itself until some process is finished. Much like this:
public async Task<ActionResult> Index(string id)
{
var result = await GetAsyncData(id);
if(!result.processed)
{
return RedirectToAction("Index","Controller", new {id=id});
}
}
Everything works as expected, as soon as result.processed is true the redirect no longer occurs. My only concern is with resource handling. Would this code continue to execute if result.processed is always false, even if the user closes the browser.
If it was always false, you would eventually get an Error 310 (net::ERR_TOO_MANY_REDIRECTS). Note that this could also occur if your GetAsyncData lasts too long. I also don't see why you would write an async method that would wait for its finish while redirecting.

Long action and waiting for a new view in ASP.NET MVC 3

I'm using ASP.NET MVC3. In the view, I have a link in view that initiates a new request:
#Html.ActionLink ("Link", "LongAction", "Home")
The action "LongAction" takes a long time, and while waiting for the new view I want show an image that simulates loading a whole new view:
public ActionResult LongAction()
{
Threas.Sleep(10000);
return View();
}
You can do something like this:
User Clicks button
Show a loading GIF
POST/GET to a server endpoint
Server endpoint kicks of the long running task.
On the complete event of the ajax request hide the loader.
Notify user
You can look into binding it together with Jquery, or if you want to use something in the mvc framework you can look at the Ajax ActionLink. Either way you can hide/show the loader with javascript.
JQuery Example:
$('#userButton').click(function(){
longRunningTask();
return false;
});
function longRunningTask()
{
$('#loader').show();
$.ajax({
url: 'http://serverendpointaddress.co.uk'
}).done(function(){
//notify the user
}).always(function() {
$('#loader').hide();
});
}

How does ASP.NET MVC caching work for an AJAX request?

I'm just starting to look in to caching to improve performance and have a question about caching for an AJAX call.
I have a action which is used to query twitter and then return the results. At the moment when a user presses a button it loads a rotating gif whilst it goes off to the action to do the query and then return a partial view. jQuery then updates a div with the HTML response from the view. Normally this takes around 5 secs. They then have a more button which goes off to get more results.
What will happen if I put the CachingAttribute over this action? I know I can try it but I just want the technical side of things explained.
Thanks
Here is my Javascript:
$('#blogEntryList #moreLink').live("click", function() {
$('#morespan').toggle();
$('#loader').toggle();
$.get($(this).attr("href"), function(response) {
$('#blogEntryList ol').append($("ol", response).html());
$('#blogEntryList #moreLink').replaceWith($("#moreLink", response));
$('#loader').hide();
$('#morespan').show();
});
return false;
});
Here is my modified Action:
[OutputCache(
Location = OutputCacheLocation.Server,
Duration = 100,
VaryByParam = "")]
public ActionResult BlogPosts(int? entryCount)
{
if (!entryCount.HasValue)
entryCount = defaultEntryCount;
int page = entryCount.Value / defaultEntryCount;
IEnumerable<BlogData> pagedEntries = GetLatestEntries(page, defaultEntryCount);
if (entryCount < totalItems)
AddMoreUrlToViewData(entryCount.Value);
return View("BlogEntries", pagedEntries);
}
Here's how it works: assuming no caching specified on the server side, by default GET requests will be cached by the browser and POST requests not cached unless you specify the cache: true attribute when sending the AJAX requests which allows you to override the client caching strategy.
Now on the server side you could decorate your controller action with the [OutputCache]
which will allow you to define different caching strategies. You could keep a cache on the server, on downstream proxy servers, or on the client. You could also manage different expiration policies.
So let's illustrate this by an example:
[OutputCache(
Location = OutputCacheLocation.Server,
Duration = 10,
VaryByParam = "")]
public ActionResult Hello()
{
return Content(DateTime.Now.ToLongTimeString(), "text/plain");
}
And on the client side:
$.ajax({
url: '/home/hello',
type: 'post',
success: function (result) {
alert(result);
}
});
The result of this controller action will be cached on the server for 10 seconds. This means that the server will be hit on each request but the action won't be executed if there's a cached version and will directly served from this cache. 10 seconds later from the first request which hit the controller action the cache will expire and the same process repeats.

Loading Page for ASP.Net MVC

I'm using ASP.Net MVC to create a web site which needs to do some processing (5 - 10 seconds) before it can return a view to the user. Rather than leaving the user staring at the glacial progress bar I'd like to show some sort of "Please Wait/We'll be right back" animated gif to keep them interested.
Does anyone know a good approach to achieving this?
(I found this answer but its not quite what I need, this uses jQuery to fetch data once the view has been returned. I'd like to display the "Please Wait" while they're waiting for the view to appear)
Thanks
I think the solution you referenced will work for you. You just need to have your initial controller action return right away with the "please wait message", then have the AJAX call do the actual retrieval of the contents based on your processing. If the request really takes 5-10 seconds you may also need to adjust the timeout value on the AJAX request so that it is able to complete. I don't know what the default timeout is but is may be less than what you need.
EDIT Example:
View code:
<script type="text/javascript">
$(document).ready( function() {
$.ajax({
type: "POST",
url: '<$= Url.Action("GetSlowData","Controller") %>',
data: 'id=<%= ViewData["modelID"] %>',
timeout: 15000, // wait upto 15 secs
success: function(content){
$("#container").html(content);
}
});
});
</script>
...
<div id="#container">
Please wait while I retrieve the data.
</div>
Controller
public ActionResult ViewMyData( int id )
{
ViewData["modelID"] = id;
return View();
}
[AcceptVerbs( HttpVerbs.Post )]
public ActionResult GetSlowData( int id )
{
var model = ... do what you need to do to get the model...
return PartialView(model);
}
You'll also need a partial view (ViewUserControl) that takes your model and renders the view of the model. Note that this isn't complete -- you'll need to add error handling, you may want to consider what happens if javascript isn't enabled, ...

Resources