MVC控制器无法执行Async方法

dav*_*off 9 c# task async-await asp.net-mvc-4

我有一个非常基本的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                
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是常规操作(不是异步版本)无法执行异步方法.在我的情况下,OpenConnection()方法总是挂起等待connection.OpenAsync()行.

过了一段时间,我发现了两种使代码正常工作的方法.

  1. 使控制器的操作异步

    public async Task<ActionResult> Index()
    {
        await OpenConnection();
    
        return View();
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 或者允许异步执行而不捕获原始SychronizationContext - 为此:

    await connection.OpenAsync();

    用...来代替:

    await connection.OpenAsync().ConfigureAwait(false);

所以,我的猜测是我最初的问题是在SynchronizationContext周围.但是SynchronizationContext.Current不是null,这让我想知道我的猜测是否正确.

那么,任何人都可以解释一下,为什么MVC控制器中的异步操作不能同步执行异步方法?

Dav*_*her 10

Stephen Cleary有一篇关于这个问题好文章,它影响了ASP.NET和桌面应用程序.基本要点是因为您的显式.Wait()调用同步阻止了上下文(示例中的ASP.NET请求上下文),异步任务无法在上下文中运行代码以通知它已完成,因此它陷入僵局.

他还提出了与您相同的两个解决方案(从顶层控制器方法一直使用async或更改异步"库"代码以不捕获上下文).