ASP.NET Core - Why async await is useful

9/17/2022
3 minute read

Did you ever wonder why you "should" use async and await in your ASP.NET Core applications? Most probably, you heard something about performance. And there is some truth to it, but not in the way you might think.

Have a look at the following asynchronous controller code:

[HttpGet]
public async Task<IActionResult> GetByIdAsync(int id)
{
    var entity = await repository.GetByIdAsync(id);
    return Ok(entity);
}

And here the "sync" version of it:

[HttpGet]
public IActionResult GetById(int id)
{
    var entity = repository.GetById(id);
    return Ok(entity);
}

They look pretty much the same, so Why should I prefer the async version here even if it seems more complex? The answer is not performance, as in it runs faster. The answer is: It scales better. Let's dissect the synchronous version for a moment. When we hit repository.GetById(...), the current worker thread stops and has to wait until the job is done. Most likely, you have a DocumentDb or SQL Server that does the real work. And these are not even local. They are on a different machine, so your server is literally idling until the answer comes back. Once this happens, your controller returns.

Now let's check the async version: Here, we also have to wait for the repository to finish its stuff, but there is a key difference. The await keyword allows the current worker thread to "detach" from the program and go back to the thread pool. Once GetByIdAsync is done, .NET will take another thread from the pool and continue the work. Now, the runtime will be the same. Obviously, it could even be that the async version is slightly (in the sense of measurable but not important) slower. But we return the thread to the thread pool and pick it up once the async stuff is finished. This is important for one thing: Scalability.

You see everytime you make a request against your server, a new worker thread will process your stuff. When you return the thread, when it just idles around, you can utilize that thread to make process another request. That is why async and await are powerful in combination with ASP.NET Core.

Another small example: Imagine you have a server that only has one available worker thread in the pool. Also two requests are coming in shortly one after another. In the synchronous version only the first request can be dealt with as there are no free threads available anymore. In the asynchronous version the second request can be immediately handled once the first request reached to the await repository.GetByIdAsync(...) line. The second request also encounters this line and returns that one thread back to the pool, which immediately gets picked up by request 1 to return the answer. Later we can then return the answer for request 2.

Sure, this is a made-up scenario, which I hope you don't run into, but it also shows the power of async and await. Instead of not being able to serve all requests, we are now able to, even though it might take a bit longer.

Conclusion

Asynchronous programming in ASP.NET Core is a super efficient way of scaling your web application. You can fully utilize your server and system resources are not just idling around!

Create your own Validationattribute in ASP.NET Core

In this small blog post, I will show you how to create your own Validation attribute in ASP.NET Core to tailor-made your validation rules.

What is a Middleware and how to use it in ASP.NET Core?

Did you ever ask yourself: What is a middleware, and why should I use it?

If so, this blog post is exactly for you. We will see where we could use a middleware and also how we can use the Dependecy Injection container of ASP.NET Core.

The state machine in C# with async/await

You often here that the async/await keywords leads to a state machine. But what does that mean? Let's discuss this with a simple example.

An error has occurred. This application may no longer respond until reloaded. Reload x