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或类似事件?

MVC应用程序中的异步调用死锁

问题就在这里:

_versionInfoViewModelMapper.Map().Result;

如果存在SynchronizationContext集(在ASP环境中是这样(,则调用Task.ResultTask.Wait()可能会导致严重的死锁。

相反,使用异步版本的方法:

public async Task<ActionResult> VersionInfo()
{
    var version = await _versionInfoViewModelMapper.Map();
    return View(version);...
}

有关此问题的更多信息,请参阅Stephen Cleary的博客文章