I have a very basic MVC controller with one action:
public class HomeController : Controller
{
public ActionResult Index()
{
OpenConnection().Wait();
return View();
}
private async Task OpenConnection()
{
var synchronizationContext = SynchronizationContext.Current;
Debug.Assert(synchronizationContext != null);
using (
var connection =
new SqlConnection(
@"Data Source=(localdb)\ProjectsV12;Initial Catalog=Database1;Integrated Security=True;"))
{
await connection.OpenAsync(); // this always hangs up
}
}
}
The problem is that regular action (not async version) can't execute async methods. In my case OpenConnection() method always hangs up at await connection.OpenAsync() line.
After sometime I found two ways to make this code working.
Make controller's action asynchronous
public async Task<ActionResult> Index()
{
await OpenConnection();
return View();
}
Or allow async execution without capturing original SychronizationContext - for that:
await connection.OpenAsync();
replace with:
await connection.OpenAsync().ConfigureAwait(false);
So, my guess is that my initial problem was somewhere around SynchronizationContext. But SynchronizationContext.Current is not null and that makes me wonder if my guess is correct.
So, could anybody explain, why not async action in MVC controller can't syncronously execute async methods?
Stephen Cleary has a good blog post about this issue and it affects both ASP.NET and desktop apps. The basic gist is that because the context (ASP.NET request context in your example) is being synchronously blocked by your explicit .Wait() call, the async Task can't run code on the context to notify that it has been completed so it deadlocks.
He also proposes the same two solutions as you (use async all the way down from the top-level controller method or change your async "library" code to not capture the context).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With