我有一个非常基本的MVC控制器,只有一个动作:
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
}
}
}
问题是常规操作(不是异步版本)无法执行异步方法。在我的情况下,OpenConnection()方法总是在 await connection.OpenAsync()行挂起。
过了一段时间后,我找到了两种方法来使这段代码正常工作。
使控制器的操作异步
public async Task<ActionResult> Index()
{
await OpenConnection();
return View();
}
或者允许异步执行而不捕获原始SychronizationContext - 为此:
await connection.OpenAsync();
替换为:
await connection.OpenAsync().ConfigureAwait(false);
所以,我的猜测是我的初始问题是在SynchronizationContext周围。但是SynchronizationContext.Current不是null,这让我想知道我的猜测是否正确。
那么,有人可以解释一下,为什么MVC控制器中的 not async 动作不能同步执行异步方法?
答案 0 :(得分:10)
Stephen Cleary有一个good blog post about this issue,它会影响ASP.NET和桌面应用。基本要点是因为您的显式.Wait()调用同步阻止了上下文(示例中的ASP.NET请求上下文),异步任务无法在上下文中运行代码以通知它已被完成所以它陷入僵局。
他还提出了与您相同的两个解决方案(从顶层控制器方法一直使用async或更改您的异步&#34;库&#34;代码以不捕获上下文)。