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

时间:2015-09-22 12:55:11

标签: c# asp.net-mvc asp.net-web-api asp.net-mvc-5.2

我们希望在所有页面的底部显示我们后端服务的版本详细信息。

3个后端服务是异步webapi(2.2)调用,我们需要让这3个异步调用将日期聚合到模型中,然后将其传递给View。

如果我将此作为(非子)控制器操作的一部分,代码将工作并显示数据。

但是,尝试在每个页面的底部显示此数据(子操作)会产生几种不同的异步死锁类型条件。

子操作并调用_layout.cshtml

read

由于请求没有结束,这导致似乎是死锁,

使用ActionFilter

    //ControllerAction
    [ChildActionOnly]
    public ActionResult VersionInfo()
    {
        var version = _versionInfoViewModelMapper.Map().Result;
        return View(version);...
    }

//Layout.cshtml
    @if(Request.IsAuthenticated)
    {
        Html.RenderAction("VersionInfo", "Utils");
    }

使用上面的过滤器将数据传递给随后使用的ViewBag,给出相同的无限通话。

如果我在异步调用中不使用.Result,则会出现错误

  

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

有没有办法解决这个问题?可能通过使用Global.asax Application_PostAuthenticateRequest或类似事件?

1 个答案:

答案 0 :(得分:-1)

问题在于:

_versionInfoViewModelMapper.Map().Result;

如果设置了Task.Result(在ASP环境中都是如此),则调用Task.Wait()SynchronizationContext可能会导致严重的死锁。

而是使用方法的异步版本:

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

有关此问题的详细信息,请参阅this Stephen Cleary blog post