Question

I'm launching multiple ajax calls to various MVC controllers to load different parts of my page. However it seems that when this gets to the controller only one runs at a time. I'm guessing this is because by default ASP.Net MVC controllers are synchronous? I've also tested loading a page on 2 browser tabs and the second tab always waits for the first.

To get round this I've attempted to make the controller methods in question asynchronous. I've done this by doing the following

  1. Append Async to controller method name
  2. Make the controller methods return async Task
  3. Used the Task.Factory.StartNew method to do the body of work in the method in a separate thread.

For example the controller methods in question now look like this...

    public async Task<JsonResult> GetUser(int userId)
    {
        var result = await Task.Factory.StartNew(() => Task.Run(() =>
        {                
            return userService.GetUser(userId);
        })).Result;
        return new JsonResult()
        {
            Data = result,
            JsonRequestBehavior = JsonRequestBehavior.AllowGet
        };
    } 

However it still seems to be synchronous. Am I missing something or going about this completely the wrong way? I've not really used the Task Library much so may be missing something big?

Was it helpful?

Solution

No, your assumptions are most likely wrong. Your problem is likely one (or both) of two problems.

First, most web browsers have request limits that only allow a certain number of request to the same server at a time.

Second, you are probably running into a limitation of the Session object that causes multiple requests that use session to be serialized, because Session is not, itself, multi-threaded.

See http://tech-journals.com/jonow/2011/10/22/the-downsides-of-asp-net-session-state

The short answer is that if you don't use session in your action method, simply add this to the method...

[SessionState(SessionStateBehavior.Disabled)]
public class AjaxTestController : Controller
{        
    //...As above
}

If you only need to read the session, then do this:

[SessionState(SessionStateBehavior.ReadOnly)]
public class AjaxTestController : Controller
{        
    //...As above
}

There's not much you can do about the browser limitations though, since different browsers have specific request limits. These can be changed with registry (or browser config) entries (usually), but you can't force your users to do that in most cases.

OTHER TIPS

One of the important feature introduced in MVC 4.0 was of Asynchronous controllers which enables to write the asynchronous action methods. Asynchronous controller allows an operation to get performed without making the working thread idle.

When an asynchronous action is invoked, the following steps occur:

The Web server gets a thread from the thread pool (the worker thread) and schedules it to handle an incoming request. This worker thread initiates an asynchronous operation. The worker thread is returned to the thread pool to service another Web request. When the asynchronous operation is complete, it notifies ASP.NET. The Web server gets a worker thread from the thread pool (which might be a different thread from the thread that started the asynchronous operation) to process the remainder of the request, including rendering the response.

Converting Synchronous Action Methods to Asynchronous Action Methods

Following is the example of synchronous action method and the its asynchronous equivalent version.

Synchronous Controller:

public class TestController : Controller
 {
   public ActionResult Index()
    {
     return View(); 
    }
 }

Asynchronous variant of above operation:

public class TestController : AsyncController
{
   public void IndexAsync()
   {
    return View();
   }

  public ActionResult IndexCompleted()
  {
   return View();
  }
}

Steps:

  • Synchronous Controllers are the classes derived from the Controller class to implement an AsyncController instead of deriving the controller from Controller, derive it from AsyncController class. Controllers that derive from AsyncController enable ASP.NET to process asynchronous requests, and they can still service synchronous action methods.

  • Corresponding to the synchronous action method in Synchronous controller you need to create two methods for the action in asynchronous controller.First method that initiates the asynchronous process must have a name that consists of the action and the suffix "Async". The other method that is invoked when the asynchronous process finishes (the callback method) must have a name that consists of the action and the suffix "Completed".

In the above sample example, the Index action has been turned into two methods in asynchronous controller: IndexAsync and IndexCompleted.

The IndexAsync method returns void while the IndexCompleted method returns an ActionResult instance. Although the action consists of two methods, it is accessed using the same URL as for a synchronous action method (for example, Controller/Index).

Note the following about asynchronous action methods:

  1. If the action name is Sample, the framework will look for SampleAsync and SampleCompleted methods.

  2. View pages should be named Sample.aspx rather than SampleAsync.aspx or SampleCompleted.aspx. (The action name is Sample, not SampleAsync)

  3. A controller cannot contain an asynchronous method named SampleAsync and a synchronous method named Sample. If it does, an AmbiguousMatchException exception is thrown because the SampleAsync action method and the Sample action method have the same request signature.

For more details click here : http://www.counsellingbyabhi.com/2014/05/asynchronous-controllers-in-aspnet-mvc.html

mvc controllers are async in nature, how did you determine it's synchronous? The only reason could only be some lock implemented within your userService.

You can try by making a couple of hundreds of ajax calls to your web services using jquery

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top