1

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

我找到了两种方法来做到这一点

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

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

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

4

1 回答 1

2

MVC 不是很async友好,尤其是过滤器。

您可以编写自己的RenderAsyncAction扩展方法或在所有async操作中复制代码。

或者,您可以尝试一些 hack。我在我的博客上描述了为什么Result在 ASP.NET 中使用会死锁,但有一个解决方法:ConfigureAwait(false)每个 awaitin 中使用GetUserInfo

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

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

您应该能够使用GetUserInfoBlockinginOnActionExecutingRenderAction

请注意副作用:

  • 这种方法每个请求使用多个线程,因此这会降低可伸缩性。纯async方法每个线程使用多个请求,因此它提高了可伸缩性。
  • 任何异常GetUserInfo都将包含在 中AggregateException,因此请确保您的日志记录将捕获InnerException详细信息,否则您将在日志中得到无意义的错误。

绝对最好async一直向下使用而不是像这样阻塞。但有时 MVC 并没有给你留下选择的余地(希望这在未来会有所改变)。

于 2012-12-04T13:46:02.037 回答