Why Would Multiple Simultaneous Ajax Calls to the Same ASP.NET MVC Action Cause the Browser to Block

Why would multiple simultaneous AJAX calls to the same ASP.NET MVC action cause the browser to block?

The answer was staring me in the face.

ASP.NET Session State Overview:

Access to ASP.NET session state is exclusive per session, which means that if two different users make concurrent requests, access to each separate session is granted concurrently. However, 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.

Annoyingly I'd skimmed paragraph this a couple of weeks ago not really taking in the full impact of the bold sentences. I had read that simply as "access to session state is serialised" and not "all requests, no matter whether you touch session state or not, are serialised" if the requests came from the same session.

Fortunately there is a work around in ASP.NET MVC3 and its possible to create session-less controllers. Scott Guthrie talks about these here:

Announcing ASP.NET MVC 3 (Release Candidate 2)

I installed MVC3 RC2 and upgraded the project. Decorating the controller in question with [SessionState(SessionStateBehavior.Disabled)] solves the problem.

And of course typically I just found this in Stack Overflow a few minutes ago:

Asynchronous Controller is blocking requests in ASP.NET MVC through jQuery

Ajax jQuery multiple calls at the same time - long wait for answer and not able to cancel

That is due to the maximum number of connections of the browser to a single domain.

See Browserscope for mamimum per browser.

  • IE 8+9: 6 connections
  • IE 10: 8 connections
  • Chrome 26: 6 connections
  • Firefox 21: 6 connections

What you could do is collect all Defferred objects and cancel them when the use clicks on a link.

example:

// some ajax calls
doAjax({});
doAjax({});

var requests = [];

// helper function to perform and register calls
function doAjax(options) {
var jqXHR= $.ajax(options);
requests.push(jqXHR);
jqXHR.always(function(jqXHR) {
var index = requests.indexOf(jqXHR);
if (index!=-1) {
requests.splice(index, 1);
}
});
}

// function to abort all calls
// when your application has a router to provide navigation, this function
// is typically called when you navigate to another page
function abortAllPendingRequests() {
var i;
for (i=0; i<requests.length; i++) {
var xhr = requests[i];
// already finished calls (readyState 4) should not be aborted
if (xhr.readyState != 4) {
xhr.abort();
}
}
};

All is left is calling the abortAllPendingRequests function when the user tries to navigate to another page.

When you have some sort of router (e.g. Backbone.Router) you could call it there.

If your application does not have a router for navigating, but you make use of plain anchor links, you could add an onClick to the links which calls the abortAllPendingRequests function.

asp.net mvc 4 controller execute multiple ajax calls in parallel

The issue you are facing is caused by the way ASP.NET is managing session. Here is the most important part from ASP.NET Session State Overview (Concurrent Requests and Session State section):

Access to ASP.NET session state is exclusive per session, which means that if two different users make concurrent requests, access to each separate session is granted concurrently. However, 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.

You can resolve your issue if your actions doesn't require access to session. If that is the case, you can decorate the controller with SessionStateAttribute attribute:

[SessionState(SessionStateBehavior.Disabled)]

This way the controller will not have to wait for session.

If your actions require only read access to session, you can try using the SessionStateBehavior.ReadOnly value. This will not result in an exclusive lock but the request will still have to wait for a lock set by a read-write request.

AJAX call being blocked

It appears to be related to another StackOverflow question on Blocked AJAX calls from MVC, which was resolved by changing session behavior.

I appear to have solved my problem by:

1) Setting AJAX called to have readonly access to session state by default, setting <%@ Page Language="C#" Async="true" EnableSessionState="ReadOnly" %> at the top of my AJAX page.

2) Allow read/write access to session state when my report generator AJAX query is running HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Required);

So far in production this appears to have solved the issue. I'll accept this answer if in 24 hours it's still running smoothly.

However I'm still puzzled by the blocking behavior not happening straight away, but only after a certain number of requests have been made.

ASP.NET MVC + jQuery + IIS6: Multiple Ajax requests

In theory, ASP.NET with Session state enabled locks the session for each user request, thus processing them serially. I don't think you can disable Session for an MVC project painlessly, because TempData for example uses session by default. But you can try.

EDIT: here's a related question



Related Topics



Leave a reply



Submit