调用异步子操作

时间:2015-09-11 18:08:27

标签: asp.net-mvc asp.net-mvc-3 asp.net-mvc-4 asp.net-web-api

我的ASP.NET MVC _Layout.cshtml在LayoutController中调用了一个子动作同步版本的“AdminMenu”,它决定了要渲染的菜单选项。在子操作中,它异步调用远程webapi。问题是,当应用程序启动时,菜单没有显示,但是会在屏幕上显示一次或两次菜单。从WebApi获得响应有一个延迟,我不知道如何解决它。我认为async方法会在菜单完成时自动更新菜单,但事实并非如此。

替代方案,我尝试调用aync版本“AdminMenu2”,我总是得到以下错误。谢谢你的帮助。

    HttpServerUtility.Execute blocked while waiting for an asynchronous 
operation to complete. Description: An unhandled exception occurred during 
the execution of the current web request. Please review the stack trace for 
more information about the error and where it originated in the code. 
Exception Details: System.InvalidOperationException: HttpServerUtility.Execute 
blocked while waiting for an asynchronous operation to complete. Source Error: 
Line 50: </ul>
Line 51: <ul class="nav navbar-nav navbar-right">
Line 52:   @Html.Action("AdminMenu", new { Controller = "Layout" }) 
Line 53: 
Line 54:   <li class="dropdown-toggle">


        Source File: c:\..\..\..\..\..\..\..\Views\Shared\_Layout.cshtml Line: 52

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using Newtonsoft.Json;
using myHelpersLib;
using mycModel;

namespace myMVC.Controllers {
  public class LayoutController: BaseController {
    [ChildActionOnly]
    public ActionResult AdminMenu() {

      string viewName = string.Empty;
      WebApiUserModel thisUser = new WebApiUserModel();
      if (Session["userProfile"] != null) {
        thisUser = (WebApiUserModel) Session["userProfile"];
      } else {
        //make webapi call to webapi/user 
        var response = GetUserProfile().ContinueWith(x => {
          //do something with the result
          if (x.IsCompleted) {
            thisUser = x.Result;
          }
        });
      }

      return PartialView(thisUser);
    }

    [ChildActionOnly]
    public async Task < ActionResult > AdminMenu2() {
      WebApiUserModel thisUser = new WebApiUserModel();
      if (Session["userProfile"] != null) {
        thisUser = (WebApiUserModel) Session["userProfile"];
      } else {
        HttpClient httpClient;
        HttpResponseMessage response;

        string svcLocation = System.Configuration.ConfigurationManager.AppSettings["WebApiEndpoint"];
        httpClient = myHelpersLib.WebApiBorker.GetClient(svcLocation);
        response = await httpClient.GetAsync("user");
        WebApiUserModel userProfile = new WebApiUserModel();
        if (response.IsSuccessStatusCode) {
          string content = await response.Content.ReadAsStringAsync();
          userProfile = JsonConvert.DeserializeObject < WebApiUserModel > (content);
          if (userProfile.Role != null)
            userProfile.Role = userProfile.Role.Trim();
        }
      }

      return PartialView(thisUser);
      //return new EmptyResult();
    }

    private async Task < WebApiUserModel > GetUserProfile() {
      HttpClient httpClient;
      HttpResponseMessage response;

      string svcLocation = System.Configuration.ConfigurationManager.AppSettings["fsrWebApiEndpoint"];
      httpClient = myHelpersLib.WebApiBorker.GetClient(svcLocation);
      response = await httpClient.GetAsync("user");
      WebApiUserModel userProfile = new WebApiUserModel();
      if (response.IsSuccessStatusCode) {
        string content = await response.Content.ReadAsStringAsync();
        userProfile = JsonConvert.DeserializeObject < WebApiUserModel > (content);
        if (userProfile.Role != null)
          userProfile.Role = userProfile.Role.Trim();
      }
      return userProfile;
    }
  }
}

2 个答案:

答案 0 :(得分:1)

  

我认为async方法会在菜单完成时自动更新菜单,但它不会。

不,async不会更改HTTP协议。每个请求仍然只有一个响应。

如果您希望在显示网页后动态更新网页,则需要使用SignalR,AJAX或某些类似技术。

正如其他人所说,不支持异步子操作(但是,ASP.NET vNext确实支持它们)。

  

它使用httpClient调用webapi,httpClient只有异步GetAsync()和ReadAsStringAsync()

如果您确实希望将其作为子操作,那么它必须是同步的。您可以使用WebClient进行同步WebAPI调用。

答案 1 :(得分:0)

实际上,子动作不能异步运行(+)。

  

建议的方法是避免在子操作中使用异步代码。

Support asynchronous child actions

相关问题