Parallel processing of concurrent Ajax requests in Asp.Net MVC

If you develop web applications that relies on JavaScript to update the interface and you use several Ajax calls inside a single page, then you should know that all those calls are not executed in parallel on the server. On a default controller, each call to an action locks the user’s Session object for synchronization purposes, so even if you trigger three calls at once from the browser, these calls will get queued and executed one by one.

In order to speed up the requests processing you should reduce the number of actions that needs to write in the Session object or TempData to a minimum and make a dedicated controller for them. The rest of the actions can now be executed in parallel using controllers that are only reading values from Session. 

If you want to enable a certain controller to process requests in parallel from a single user, you can use an attribute named SessionState that was introduced in MVC since version 3. It’s not necessary to use a session-less controller in order to achieve parallelism, the Ready-only option of the SessionStateBehavior will let you pass security checks you may have implemented based on Session data.

ParallelController.cs
    [SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
    [OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
    public class ParallelController : Controller
    {
        public JsonResult Get1()
        {
            //read from session
            var x = Session["call"];
            Thread.Sleep(5000);
            return Json(new { obj = "p1" }, JsonRequestBehavior.AllowGet);
        }

        public JsonResult Get2()…
        public JsonResult Get3()…
    }

The serial controller has the same actions but writes data in the session object:

SerialController.cs
    [SessionState(System.Web.SessionState.SessionStateBehavior.Required)]
    [OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
    public class SerialController : Controller
    {
        public JsonResult Get1()
        {
            //write to session
            Session["call"] = "call";
            Thread.Sleep(5000);
            return Json(new { obj = "s1" }, JsonRequestBehavior.AllowGet);
        }

        public JsonResult Get2()…
        public JsonResult Get3()…
    }

Calling both controllers from jQuery at document ready:

Index.cshtml
    $(document).ready(function () {

        start = new Date().getTime();

        for (i = 1; i <= 3; i++) {
            $.ajax('Parallel/Get' + i, {
                cache: false
            }).done(logParallel);
        }

        for (i = 1; i <= 3; i++) {
            $.ajax('Serial/Get' + i, {
                cache: false
            }).done(logSerial);
        }

    });

In Firebug you can see on the Network tab, that all six calls are fired at once and all calls made to the parallel (SessionStateBehavior.ReadOnly) controller returns in 5 seconds along with the first call that reached the serial (Read-Write Session) controller. The Get2 call to the serial controller will wait for Get1 to complete, and Get3 will wait for Get2, lasting 10 seconds longer overall. The Firebug timeline is more accurate then my js date diff.

The result showed here where taken with the project hosted on a dedicated Webserver. On my home pc, sometimes, the results got messed up because the browser can fire some calls  too late or, on the server side, the call is queued inside the ThreadPull for a thread that is already busy. Azure would be a good place to host this test.

Prerequisites & Download

In order to easily install all the prerequisites you can use the Web Platform Installer version 4.

download source code files

18 Responses to Parallel processing of concurrent Ajax requests in Asp.Net MVC
  1. Vinny Reply

    Hey, is this only for 4.0? Do you know if ~3.5 has a features like this?

    Great post!
    Thanks,

    • stefan Reply

      SessionStateBehavior Enumeration was first implemented in .NET Framework v4.0, in .net 3.5 you can use a session-less WCF service.

  2. [...] Parallel processing of concurrent Ajax requests in Asp.Net MVC - Stefan Prodan discusses the standard be... blog.cwa.me.uk/2012/02/14/the-morning-brew-1043
  3. Jef Claes Reply

    Interesting, I had no idea. Thanks!

  4. Andrei Rinea Reply

    Can’t you just set SessionState to off in web.config? [Supposing you are not using it at all throughout the site]. I’ve seen this in an answer on Stackoverflow.

  5. Andrei Ignat Reply

    IT would be interesting if ,in Session_Start, you put 3 vars in Session – just string,s let’s say, and re-do the testing.

  6. Phu Tang Reply

    Very interesting. Thanks

  7. Imran Baloch Reply

    I have also written a similar article 1.5 years ago at, http://weblogs.asp.net/imranbaloch/archive/2010/07/10/concurrent-requests-in-asp-net-mvc.aspx. It also shows you how to do the same in in MVC 1/2.

  8. jagz w Reply

    I don’t understand the timing of Serial processing of Ajax calls.

    If first call is completed in 5115ms then second call takes 10149ms?
    Or
    Second call = 10149-5115=5034ms

    • stefan Reply

      Second call takes 10149 because it waits for the first call to complete, so 5115ms wait time and 5034ms process time.

  9. Parallel processing of concurrent Ajax requests in Asp.Net MVC... Thank you for submitting t... bluerayplus.com/Parallel-processing-of-concurrent-Ajax-requests-in-AspNet-MVC
  10. Drogon Reply

    Is this only for action methods using session or tempdata? I don’t seem to have a problem making parallel calls to action methods that don’t use session…

  11. Niti Reply

    Nice. Thanks 4 sharing.

  12. alexandru pascanu Reply

    I want to do the same thing but from a silverligth client.More exactlly i want to upload multiple files -every file on it thread and the POST controller to save the files on the disc but every operation on it’s owne thread.
    Thanks

    • stefan Reply

      For multiple uploads I would recommend using WCF with MTOM encoding, MTOM is a mechanism for transmitting large binary attachments with SOAP messages as raw bytes. You can easily do multi-threading over WCF by using the PerCall service behavior.

  13. Manoj Reply

    Very interesting. Thanks

  14. Rajeev Reply

    Can anyone explain how it works if I am not using any session object except of session id that gets created in my aspstate/ASPStateTempSessions table in database. On every call to my controller action Expires field gets updated. So, I use SessionStateBehavior.Readonly then “expires” field won’t get updated?

  15. Matt F Reply

    Thank you for this–such a simple solution for concurrent ajax requests.

Leave a Reply

Your email address will not be published. Please enter your name, email and a comment.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>