1

We want to display version detail from our back end services on the bottom of all pages.

The 3 backend services are async webapi(2.2) calls, we need to make these 3 async calls aggregate the date into a model and then pass that to the View.

If i do this as part of a (not-child) controller action the code works and displays the data.

However trying to display this data at the bottom of every page (child action) gives several differing async deadlock type conditions.

child action and call on _layout.cshtml

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

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

This results in what seems to be a deadlock as the request doesn't end,

using An 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;
        }
    }

using the above filter to pass the data to the ViewBag which is then used, gives the same endless call.

If I don't use the .Result on the async calls i get an Error

HttpServerUtility.Execute blocked while waiting for an asynchronous operation to complete.

Is there a way i can get around this issue? potentially by using a Global.asax Application_PostAuthenticateRequest or similar event?

Tim
  • 7,401
  • 13
  • 61
  • 102
  • 1
    It seems async is not supported in child actions, see [this question](http://stackoverflow.com/questions/12739114/asp-net-mvc-4-async-child-action) or [this other question](http://stackoverflow.com/questions/28680288/mvc-async-child-actions-not-working-in-iis). The request [in codeplex](http://aspnetwebstack.codeplex.com/workitem/601) was closed as "added in MVC 6 as part of the View Components" – Daniel J.G. Sep 22 '15 at 13:04
  • Does wrapping with `Task.Run` not work? – Kędrzu Sep 22 '15 at 13:08
  • yeah thats why i came to this issue after initially trying an async child action. – Tim Sep 22 '15 at 13:08
  • @Kędrzu i cannot remember which of the error states it gave but that failed as well you can see i had this commented out in the actionfilter attempt. – Tim Sep 22 '15 at 13:09

1 Answers1

-1

The problem lies here:

_versionInfoViewModelMapper.Map().Result;

Calling Task.Result, as well as Task.Wait() in case there is a SynchronizationContext set (which is true in ASP environment) may lead to serious deadlocks.

Instead use async version of your method:

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

For more info about this problem see this Stephen Cleary blog post

Kędrzu
  • 2,385
  • 13
  • 22
  • you cannot have async child tasks, i started with this and got errors which resulted in me investigating other methods. follow links off this http://stackoverflow.com/questions/29519253/awaited-async-method-not-returning-before-result-is-required – Tim Sep 22 '15 at 13:05
  • Yes, I just investigated this. – Kędrzu Sep 22 '15 at 13:08