5

In a legacy MVC 5 web app I want the user to be able to continue browsing after clicking a button which makes an ajax call to a long running action.

(Note: The action returns void - I am not interested in the response)

When I click the button I am unable to make any other requests until the action completes.

Edit: Here is the ajax code:

$('#EmailReport') //
    .click(function() {
        $.ajax({
            type: "POST",
            url: '/Home/EmailReport',
            complete: function() {console.log("done")},
            async: true
        });
    });

Controller

[HttpPost]
public async Task EmailReport()
{
   // for testing - sleep for 10 seconds
   await Task.Delay(TimeSpan.FromSeconds(10));
}

Here is a screenshot in Chrome dev tools:

Ajax request

EmailReport is the ajax call, the two requests at the bottom are me trying to browse to another page - as you can see the first request is pending and any subsequent requests are cancelled

Does anyone have any ideas how I can resolve or troubleshoot this issue?

Vinyl Warmth
  • 2,226
  • 3
  • 25
  • 50

4 Answers4

2

The problem is that, your action waits for completion of the task. Don't make it wait and return as soon as you start the task.

[HttpPost]
public void EmailReport()
{
   // for testing - sleep for 10 seconds
   var myTask = Task.Delay(TimeSpan.FromSeconds(10));
   myTask.Start();
}

Your request is cancelled because it is a page redirect request and old page redirect requests are cancelled when a new one is issued (e.g. when you click a link 2 times, first click is ignored). It is the way browsers implement it. It is not related with the root of your problem.

Gokhan Kurt
  • 8,239
  • 1
  • 27
  • 51
  • Thanks for your answer - I made this change but now when I look at the ajax call in dev tools network tab I am getting a 500 error? – Vinyl Warmth Oct 03 '16 at 09:16
  • Can you post the exception? You can find the exception in `Application_Error` method of `Global.asax` with `Server.GetLastError()`. See https://forums.asp.net/t/1926670.aspx?How+to+get+last+exception – Gokhan Kurt Oct 03 '16 at 09:31
1

The simplest way would be as follows :

Task t = new Task(() => TimeSpan.FromSeconds(10));
t.Start();

It is better to use Task as compared to thread for long running jobs to avoid core affinity and better CPU utilisation.

Rahul Jain
  • 3,130
  • 1
  • 14
  • 16
0

Use background process

[HttpPost]
public JsonResult EmailReport()
{
    Thread email= new Thread(delegate ()
   {
          generatereports();
   });
   email.IsBackground = true;
   email.Start();
   return null; 
}
Mannan Bahelim
  • 1,289
  • 1
  • 11
  • 31
0

it seems Navigator.sendBeacon() api will serve your purpose. it is used to asynchronously transfer a small amount of data over HTTP to a web server. though this is an experimental technology, supported in Chrome 39+, Firefox 31+, opera 26+, there is a polyfill for other browsers.

Sufian Saory
  • 862
  • 9
  • 14