如何在每个操作中使用async在MVC4中为_Layout设置ViewBag

时间:2012-12-04 10:17:18

标签: asp.net-mvc asp.net-mvc-4 async-await

用例很简单。登录用户的信息显示在_Layout.cshtml中。这些信息每次都需要刷新。

我发现了两种方法

  • 拥有BaseController及其OnActionExecuting方法集ViewBag.UserInfo = ...;,后来在_Layout.cshtml中使用
  • _Layout.cshtml执行@{Html.RenderAction("GlobalUserInfo", "UserInfo");}

问题是,如果从异步public async Task<UserInfo>GetUserInfo(){...}方法返回UserInfo,这两种方法会因死锁或异常而失败。

所以问题是这样的:当使用async / await检索数据时,如何在每个动作上设置ViewBag属性。

1 个答案:

答案 0 :(得分:2)

MVC并不完全async - 友好,尤其是过滤器。

您可以编写自己的RenderAsyncAction扩展程序或在所有async行动中复制代码。

或者,您可以尝试一些黑客攻击。我在我的博客why using Result in ASP.NET can deadlock上进行了描述,但有一种解决方法:在ConfigureAwait(false)的每个 await上使用GetUserInfo

然后你可以定义一个同步包装器:

public UserInfo GetUserInfoBlocking()
{
  return GetUserInfo().Result;
}

您应该可以在GetUserInfoBlockingOnActionExecuting中使用RenderAction

请注意副作用:

  • 此方法每个请求使用多个个线程,因此这将降低可伸缩性。纯async方法每个线程使用多个请求,因此增加了可伸缩性。
  • 来自GetUserInfo的所有例外情况都将包含在AggregateException中,因此请确保您的日志记录会捕获InnerException详细信息,否则您的日志中会出现毫无意义的错误。

最好始终使用async而不是像这样阻止。但有时MVC并没有给你一个选择(希望将来会改变)。