When should I use Async Controllers in ASP.NET MVC?

Vnuuk picture Vnuuk · Jun 1, 2015 · Viewed 113k times · Source

I have some concerns using async actions in ASP.NET MVC. When does it improve performance of my apps, and when does it not?

  1. Is it good to use async action everywhere in ASP.NET MVC?
  2. Regarding awaitable methods: shall I use async/await keywords when I want to query a database (via EF/NHibernate/other ORM)?
  3. How many times can I use await keywords to query the database asynchronously in one single action method?

Answer

Stephen Cleary picture Stephen Cleary · Jun 1, 2015

You may find my MSDN article on the subject helpful; I took a lot of space in that article describing when you should use async on ASP.NET, not just how to use async on ASP.NET.

I have some concerns using async actions in ASP.NET MVC. When it improves performance of my apps, and when - not.

First, understand that async/await is all about freeing up threads. On GUI applications, it's mainly about freeing up the GUI thread so the user experience is better. On server applications (including ASP.NET MVC), it's mainly about freeing up the request thread so the server can scale.

In particular, it won't:

  • Make your individual requests complete faster. In fact, they will complete (just a teensy bit) slower.
  • Return to the caller/browser when you hit an await. await only "yields" to the ASP.NET thread pool, not to the browser.

First question is - is it good to use async action everywhere in ASP.NET MVC?

I'd say it's good to use it everywhere you're doing I/O. It may not necessarily be beneficial, though (see below).

However, it's bad to use it for CPU-bound methods. Sometimes devs think they can get the benefits of async by just calling Task.Run in their controllers, and this is a horrible idea. Because that code ends up freeing up the request thread by taking up another thread, so there's no benefit at all (and in fact, they're taking the penalty of extra thread switches)!

Shall I use async/await keywords when I want to query database (via EF/NHibernate/other ORM)?

You could use whatever awaitable methods you have available. Right now most of the major players support async, but there are a few that don't. If your ORM doesn't support async, then don't try to wrap it in Task.Run or anything like that (see above).

Note that I said "you could use". If you're talking about ASP.NET MVC with a single database backend, then you're (almost certainly) not going to get any scalability benefit from async. This is because IIS can handle far more concurrent requests than a single instance of SQL server (or other classic RDBMS). However, if your backend is more modern - a SQL server cluster, Azure SQL, NoSQL, etc - and your backend can scale, and your scalability bottleneck is IIS, then you can get a scalability benefit from async.

Third question - How many times I can use await keywords to query database asynchronously in ONE single action method?

As many as you like. However, note that many ORMs have a one-operation-per-connection rule. In particular, EF only allows a single operation per DbContext; this is true whether the operation is synchronous or asynchronous.

Also, keep in mind the scalability of your backend again. If you're hitting a single instance of SQL Server, and your IIS is already capable of keeping SQLServer at full capacity, then doubling or tripling the pressure on SQLServer is not going to help you at all.