ASP.NET MVC 4 异步子动作

Posted

技术标签:

【中文标题】ASP.NET MVC 4 异步子动作【英文标题】:ASP.NET MVC 4 async child action 【发布时间】:2012-10-05 03:34:36 【问题描述】:

我有一个面向 .NET 4.5 的 ASP.NET MVC 4 应用程序。我们的子操作之一使用 HttpClient 调用 Web 服务。

由于我们在 IO 上阻塞等待 HttpClient 响应,因此将代码转换为 async/await 模式非常有意义。但是,当 MVC 4 尝试执行子操作时,我们会收到以下错误消息:

HttpServerUtility.Execute 在等待异步操作完成时被阻塞。

乍一看,MVC 4 似乎不支持子操作中的异步/等待。剩下的唯一选择是使用同步代码运行并在异步任务上强制“等待”。

众所周知,在 ASP.NET 上下文中的异步任务上触摸 .Result 或 .Wait() 会立即导致死锁。我的异步逻辑包装在一个类库中,所以我不能使用“await blah.ConfigureAwait(false)”技巧。请记住,在子操作上标记“异步”并使用 await 会导致错误,这会阻止我配置 await。

在这一点上,我被画到了一个角落。是否有任何方法可以在 MVC 4 子操作中使用异步方法?似乎是一个没有解决方法的完全错误。

【问题讨论】:

能否包含显示问题的最少代码? 【参考方案1】:

MVC 中仍有部分不是async-friendly;我希望这些将在未来得到解决。请为此创建一个 Connect 或 UserVoice 问题。

我的异步逻辑封装在一个类库中,所以我不能使用“await blah.ConfigureAwait(false)”技巧。

您可能应该ConfigureAwait(false) 添加到您的类库中的调用中(如果可以的话)。

您还可以破解一个替代解决方案。 如果您的类库方法不需要 ASP.NET 上下文,那么您可以让线程池线程执行 (a) 等待您:

try

    var result = Task.Run(async () =>  await MyHttpRequest(...); ).Result;

catch (AggregateException ex)  ... 

效果类似于ConfigureAwait(false):由于MyHttpRequest在线程池上下文中运行,它在完成时不会尝试进入ASP.NET上下文。

【讨论】:

查看了一些关于异步的更高级的 MSDN/Channel 9 视频,并看到了完全相同的建议。我已经更新了代码并切换到阻止子操作中的任务 - 绝对不理想,但它有效。希望他们将来能解决这个问题。我会在用户声音上投我一票:) 谢谢! 你能在这里张贴链接吗?其他资源总是有帮助的! 请注意,相关的 codeplex 和 uservoice 链接是 aspnetwebstack.codeplex.com/workitem/601 和 aspnet.uservoice.com/forums/41201-asp-net-mvc/suggestions/…。请投票。 我学到的一个有趣的优化是将“.Result”替换为“.GetAwaiter().GetResult()”。避免 AggregateException 混乱。【参考方案2】:

斯蒂芬回答的格式对我不太适用(也许这是一个异步菜鸟问题,但是嘿)。

我必须以这种格式编写异步表达式才能获得强类型返回值。

Person myPerson = Task.Run(() => asyncMethodWhichGetsPerson(id)).Result;

【讨论】:

以上是关于ASP.NET MVC 4 异步子动作的主要内容,如果未能解决你的问题,请参考以下文章

表单身份验证、ASP.NET MVC 和 WCF RESTful 服务

MVC Contrib 是不是兑现了提高 ASP.NET MVC 生产力的承诺

跟我学ASP.NET MVC之十一:URL路由

ASP.NET MVC动作方法使用Session在其它方法中无法取值

为啥总是在 asp.net mvc 中同步异步操作(async await)

处理 OAuth 2.0 身份验证 - 在 ASP.NET MVC 应用程序中获取令牌重定向令牌响应