MVC应用程序中的异步调用死锁
本文关键字:调用 死锁 异步 应用程序 MVC | 更新日期: 2023-09-27 18:13:52
我们希望在所有页面的底部显示来自后端服务的版本详细信息。
这3个后端服务是异步webapi(2.2(调用,我们需要让这3个异步调用将日期聚合到一个模型中,然后将其传递给View。
如果我这样做是作为(而不是子(控制器操作的一部分,那么代码就会工作并显示数据。
然而,试图在每个页面的底部显示这些数据(子操作(会产生几种不同的异步死锁类型条件。
子操作并调用_layout.cs.html
//ControllerAction
[ChildActionOnly]
public ActionResult VersionInfo()
{
var version = _versionInfoViewModelMapper.Map().Result;
return View(version);...
}
//Layout.cshtml
@if(Request.IsAuthenticated)
{
Html.RenderAction("VersionInfo", "Utils");
}
这导致了似乎是死锁的情况,因为请求没有结束,
使用ActionFilter
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
var viewBag = filterContext.Controller.ViewBag;
if (filterContext.RequestContext.HttpContext.Request.IsAuthenticated)
{
//viewBag.VersionInfo = Task.Run(() => _versionInfoViewModelMapper.Map()).Result;
viewBag.VersionInfo = _versionInfoViewModelMapper.Map().Result;
}
}
使用上面的过滤器将数据传递给ViewBag,然后使用它,会发出同样的无休止的调用。
如果我不使用。异步调用的结果我得到一个错误
HttpServerUtility。等待异步时执行被阻止要完成的操作。
我有办法绕过这个问题吗?可能通过使用Global.asax Application_PostAuthenticateRequest或类似事件?
问题就在这里:
_versionInfoViewModelMapper.Map().Result;
如果存在SynchronizationContext
集(在ASP环境中是这样(,则调用Task.Result
和Task.Wait()
可能会导致严重的死锁。
相反,使用异步版本的方法:
public async Task<ActionResult> VersionInfo()
{
var version = await _versionInfoViewModelMapper.Map();
return View(version);...
}
有关此问题的更多信息,请参阅Stephen Cleary的博客文章