Creating Asynchronous Actions in ASP.NET MVC

Introduction

Asynchronous actions allow you to handle more concurrent requests and can be implemented using async / await keywords. Asynchronous actions are useful in situations where you are performing some network operation such as calling a remote service. This article discusses asynchronous actions and also shows how to create them in an ASP.NET MVC.

Overview of Asynchronous Actions

Before you create an asynchronous action, let's quickly understand what asynchronous processing is with respect to ASP.NET MVC and how it is beneficial to your application.

Suppose that you are developing an ASP.NET MVC application that heavily relies on some third-party service. Consider the following action method as an example:

The above code shows an Index() action method that returns an ActionResult. Inside, it creates an instance of a helper class (DbHelper) and calls its GetCustomerData() method. The GetCustomerData() method wraps the remote service call and returns the data returned by the service as a List of Customer objects. The data is then passed to the Index view as its model.

The Index() action method shown above executes in asynchronous manner. When a request lands to the Index() action, ASP.NET picks up a thread from its thread pool and runs the Index() method on the allotted thread. Since Index() action is synchronous, all the operations, including the remote service call, happen sequentially (one after the other). Once all the operations are over, the thread running the code can be reused for some other execution. Thus a thread from the thread pool is blocked for the entire duration of the execution - start to end. Let's say this execution takes 10 seconds (just a hypothetical value).

Now assume that the Index() and GetCustomerData() method has been modified to work in asynchronous manner. When a request lands to the Index() action, ASP.NET picks up a thread from the thread pool as before. The Index() method starts running on a thread allotted to it. However, the allotted thread invokes the GetCustomerData() asynchronously and is immediately returned to the thread pool to serve other requests. When the remote service call returns the required data, another thread from the thread pool is allotted to finish the remainder of the Index() method code. Thus instead of blocking a thread for the entire duration of the processing, a thread is released as soon as the network operation starts and the processing resumes on some other thread when the network operation returns. Even in this case the total time taken for the processing is 10 seconds but the thread is freed to serve other requests. This results in improved handling of concurrent requests. Although there may not be any performance improvement as far as single requests processing time is concerned, the overall performance of the application may be better than before because there is less queuing of requests.

Synchronous operations are good when you wish to stick to a a simple programming model, operations are short running and CPU centric. On the other hand, asynchronous operations are good when concurrent request handling is more important than simplicity, operations are long running and network centric (such as remote Web API or service calls).

Creating Asynchronous Actions

Now that you know the basics of asynchronous action methods, let's create an asynchronous action method using async / await keywords of C#. To begin developing this sample application, create a new ASP.NET MVC application using empty project template. Then add an ADO.NET Entity Data Model for the Customers table of the Northwind database. The following figure shows this data model:

Customers table

Then add a class to the project and name it DbHelper. This class contains the GetCustomerDataAsync() method as shown below:

This application doesn't use any real network operation such as a service call. Just for the sake of testing, it fetches all the customers from the Customers table and returns to the caller.

The GetCustomerDataAsync() method returns a Task object that wraps a generic List of Customer entities. The GetCustomerData() is marked with the async keyword indicating that it is to be called in asynchronous manner. Since the method is asynchronous the method name ends with "Async". Inside, a LINQ to Entities query is formed that fetches all the customers from the database. Notice that the data is realized by calling ToListAsync() method. The await keyword used in the ToListAsync() statement indicates that the execution should wait for ToListAsync() to complete. The List of Customer entities is then returned to the caller.

Now, add a controller to the Controllers folder and add the following code to it:

This is the same Index() action you saw earlier but now it has been converted to its asynchronous version. The IndexAsync() method returns a Task object that wraps the ActionResult. It is also marked with an async keyword. Inside, it creates an instance of DbHelper class and calls the GetCustomerDataAsync() method. Notice the use of the await keyword. You will find that async and await always go hand in hand.

Now, add IndexAsync view to the project and add the following markup to it:

If you run the IndexAsync() action method you should get a list of customers displayed in a table (see below).

A list of customers

Dealing with Timeouts

While working with asynchronous operations you should take into account the possibility that a call is made that never returns. To tackle such situations ASP.NET MVC provides the [AsyncTimeout] attribute. The [AsyncTimeout] attribute specifies a timeout value in milliseconds for the asynchronous operation. The default timeout value is 45 seconds. Although we won't get into more detail of the [AsyncTimeout] here, you can use it as follows:

The above code sets the timeout value to 2000 milliseconds. Just in case you don't want to have any timeout or the asynchronous operation you can use the [NoAsyncTimeout] attribute.

[NoAsyncTimeout]
public async Task<ActionResult> IndexAsync()
{
...
}

Summary

ASP.NET MVC makes it easy for you to create asynchronous action methods by following the async / await pattern of .NET framework 4.5. Asynchronous operations allow action methods to cater to more concurrent requests than otherwise. Asynchronous action methods are useful for tasks involving network operations such as calling a remote service.

Related Articles

Comments

Is it necessary is it is only one call from controller

Posted by Aswin
on 08/15/2016 12:49pm

If your controller has only one service method call then is it necessary to make async call. For e.g.
List data = helper.GetCustomerData();
Since we have only one call, what is the point of going async. I understand if we have multiple backend calls like
List data = helper.GetCustomerData();
List data1 = helper.GetCustomerData1();
then it makes sense to go async so that second call doesn't have to wait until first is done.

Chain of Commands for Task<> - Is it necessary?

Posted by Amit Karmakar
on 03/27/2015 10:06am

Great Article !!!
I was wondering if we really need to complicate the helper method itself to return Task.
Can we not keep the helper layer simple and instead call make the synchronous call at the Controller Action only. Something like:
public async Task IndexAsync()
{
return await Task.Run(() = {
DbHelper helper = new DbHelper();
List data = helper.GetCustomerData();
return View(data);
});
}
This way - the subsequent layers can be implemented as normal object types and the complexity of asynchronous call is left alone only at Controller class.

Simple explanation for Async programming

Nice article (a suggestion)

Posted by SpiderCode
on 11/19/2014 08:59pm

Hello Bipin Joshi, Its a very nice article written. Enjoyed it while reading. Apart from this, I found there is a small mistake (Not sure).
In your blog, you have written that "The Index() action method shown above executes in asynchronous manner", it does not execute in asynchronous manner, it will be executed in synchronous manner :)

Confused

Posted by Logan
on 07/05/2014 08:21am

Where does .ToListAsync() come from? I'm getting a "does not contain a definition for .ToListAsync" error...
Also, where I declare my actions (ie. public async Task GetUsers()), its telling me "Cannot find all types required by the 'async' modifier...