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?
As it turns out the complete answer required two things:
Firstly (thanks Darin for confirming it) the session essentially locks the pages to be executed one after the other. Further investigation has pointed to this being a more general problem with ASP.Net sessions – they just can’t handle optimistic concurrency.
Secondly the cancelled request needs to check whether the client is still connected. There are situations where you might want to continue (like a fire and forget ASP action) but in this case if the client’s no longer waiting for the report there’s no point us continuing to process it.
This is available as a property of the response:
this.Response.IsClientConnectedSo to effectively cancel my server side action when jQuery requested it I had to write my own session handler and add regular checks against
this.Response.IsClientConnected.