Should I use await with async Action method?
To write non-blocking asynchronous code, you need to execute some kind of existing non-blocking asynchronous operation, such as Task.Delay()
, or async network or file IO.
In short, the await
keyword consumes asynchrony; it does not create it.
If you don't have any actual asynchronous work to do, await
won't do you any good.
I need to implement an asynch Action in my Controller for a long running external API call.
...
My question is, is this enough to make is truly non-block asynchronous? Do I also need to apply the await operator, and if so how should I do that?
The C# compiler is probably already suggesting the async
keyword is redundant here:
[AsyncTimeout(200)]
public async Task<ActionResult> DoAsync()
{
// Execute long running call.
return View();
}
The fact that you've added the async
keyword doesn't make your method magically run in the background.
If you do something like await Task.Run(() => View())
as suggested by another answer, you still won't break through the boundaries of a given HTTP request. The request processing will take at least as much time to generate the View
as without Task.Run
. The client-side browser will still be waiting for it.
This pattern is good for a UI app, when you need to offload a CPU-bound work to a pool thread, to avoid blocking the UI thread and keep the UI responsive. However, using it within an HTTP request handler inside an ASP.NET app is almost never a good idea. It will only hurt the performance and scalability.
One solution, providing a user-friendly experience for when the View
takes significant amount of time to compose, is to run a background task which spans the boundary of a single HTTP requests. Then further use AJAX requests to keep the client-side browser updated with the progress. Here's a great example by Alan D. Jackson, doing just that:
Long Running Background Tasks in Asp.Net MVC3.
However, running a lengthy background operation across multiple HTTP requests inside the same ASP.NET server process is not a very good idea. While it's relatively easy to implement, this approach may create issues with IIS maintainability, scalability and security.
You might be better off with a separate Windows/WCF service for that, which would expose a Task
-based API. Then use AJAX to periodically poll the WCF service, using a dedicated method of your ASP.NET MVC controller as a proxy for the polling call.