MVC 控制器无法执行异步方法
MVC controller can't execute Async method
我有一个非常基本的 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 不为空,这让我想知道我的猜测是否正确。
那么,有人能解释一下,为什么 MVC 控制器中的 not async 操作不能同步执行异步方法吗?
Stephen Cleary 有一个 good blog post about this issue,它会影响 ASP.NET 和桌面应用程序。基本要点是,因为上下文(在您的示例中为 ASP.NET 请求上下文)被显式 .Wait() 调用同步阻塞,异步任务无法在上下文中 运行 代码进行通知它已经完成,所以它死锁了。
他还提出了与您相同的两个解决方案(从顶级控制器方法一直使用异步或更改您的异步 "library" 代码以不捕获上下文)。
我有一个非常基本的 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 不为空,这让我想知道我的猜测是否正确。
那么,有人能解释一下,为什么 MVC 控制器中的 not async 操作不能同步执行异步方法吗?
Stephen Cleary 有一个 good blog post about this issue,它会影响 ASP.NET 和桌面应用程序。基本要点是,因为上下文(在您的示例中为 ASP.NET 请求上下文)被显式 .Wait() 调用同步阻塞,异步任务无法在上下文中 运行 代码进行通知它已经完成,所以它死锁了。
他还提出了与您相同的两个解决方案(从顶级控制器方法一直使用异步或更改您的异步 "library" 代码以不捕获上下文)。