Async Patterns in MVC Controllers for Efficiency or Adding Unnecessary Complexity?

Previously, as I delved into writing action methods within controllers, I followed a conventional path that seemed to get the job done. However, curiosity led me to explore alternative approaches, and what I uncovered was a diverse landscape of coding styles. It became apparent that the way I wrote my code was just one path among many. As I compared my methods with those employed by other developers, I began to question if there were significant differences in terms of logic, performance, or other aspects.

In this article, we delve into the intricacies of MVC controller methods, exploring the impact of asynchronous design choices and shedding light on the reasons behind seemingly elaborate async patterns.

As you can see below.

In MVC controllers, one method fetches users normally, while another adds 'async' without 'await.'

1. Normal action method in the controller

[HttpGet] 
public IActionResult GetUsers()
{   
    // Retrieve a list of all user objects synchronously. 
    List<User> userList = _dbService.ReadAllUsers(); 
    return View(userList); 
}

2) Action method contains async keyword without await keyword

[HttpGet] 
public async Task<IActionResult> GetUsers() 
{  
  //Do some work and get a list of all user-objects. 
  List<User> userList = _dbService.ReadAllUsers();  
  return View(userList);
}

In the first and second methods, in terms of functionality, the two provided methods will behave similarly because there's no 'await' keyword inside the 'async' method. Both methods will execute synchronously, and the actual difference is not significant in this specific example.

However, it's worth noting that the second method is declared as an asynchronous method (async Task<IActionResult>), but it doesn't actually include any asynchronous operations.

I mean, The method is declared as asynchronous (async Task<IActionResult>), but it doesn't include any actual asynchronous operations using the await keyword. The ReadAllUsers() method is called synchronously, and there is no asynchronous operation being awaited in the method.

3) The Action method contains async and await keyword

[HttpGet] 
public async Task<IActionResult> GetUsers() 
{ 
    // Do some work and get a list of all user-objects. 
    List<User> userList = await _dbService.ReadAllUsersAsync(); 
    return View(userList);
}

When you use 'await' with an asynchronous operation, like _dbService.ReadAllUsersAsync(), the method will pause and wait for the asynchronous operation to complete. Importantly, the thread is not blocked during this waiting period, allowing other tasks or operations to proceed concurrently.

However, in this specific case, where there is no additional asynchronous work to be performed while waiting for the _dbService.ReadAllLinesAsync() operation, the asynchronous version doesn't offer any noticeable advantages. Consequently, there wouldn't be a significant difference between the two methods.

All three of the above methods will function in the same way. So, why do we write in such a fancy way? 😅

In a web application, employing async and await can be advantageous, particularly when handling multiple requests. It's considered a good practice to use async and await when there are genuine asynchronous operations to execute or if there's an expectation of introducing them in the future.