Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you cancel an AJAX long running MVC action client side (in javascript)?

I have a long running (4-10 second) MVC action that runs a report from an AJAX call. While it's running users can change the parameters and run something else, so I cancel the AJAX request before making another one.

So, for instance (example in jQuery but the problem happens regardless):

// If we have an active request and it's not complete
if(dataRequest && dataRequest.readyState != 'complete') 
{
    dataRequest.abort();
}

dataRequest = $.ajax(...);

Client side this appears to work fine, but the cancelled request is still running on the server. For instance if the report takes 10 seconds, and I cancel one and start the other then the second request takes 20 seconds.

I think this is due to the session level locking:

[If] two concurrent requests are made for the same session (by using the same SessionID value), the first request gets exclusive access to the session information. The second request executes only after the first request is finished.

So the second request can't access the session until the first one finishes. Using asynchronous MVC actions doesn't seem to get around this as the action still needs to be able to make changes to the session.

Is it possible to stop one action and start the next without using AsyncController or [SessionState(SessionStateBehavior.ReadOnly)]?

If it isn't are both required?

like image 815
Keith Avatar asked Jan 18 '12 17:01

Keith


1 Answers

[SessionState(SessionStateBehavior.ReadOnly)] or completely disabling session is enough to allow concurrent access to controller actions from the same session. So the second request (from the same session) doesn't need to wait for the first to complete before being processed. As far as canceling the first action on the server is concerned, well, that will be harder. You will have to associate each task an unique id and when a new task is started return this task id to the client. Then when you cancel the AJAX request on the client by calling .abort() you could fire another AJAX request to some other controller action and pass it the unique task id. This controller action itself will set some common flag to indicate the first action to stop.

The TPL has built-in cancellation support that you might take a look to simplify that in order to avoid a shared data structure between the 2 that will synchronize them.

like image 175
Darin Dimitrov Avatar answered Oct 03 '22 10:10

Darin Dimitrov