用例很简单。登录用户的信息显示在_Layout.cshtml中。这些信息每次都需要刷新。
我发现了两种方法
BaseController
及其OnActionExecuting
方法集ViewBag.UserInfo = ...;
,后来在_Layout.cshtml中使用_Layout.cshtml
执行@{Html.RenderAction("GlobalUserInfo", "UserInfo");}
问题是,如果从异步public async Task<UserInfo>GetUserInfo(){...}
方法返回UserInfo,这两种方法会因死锁或异常而失败。
所以问题是这样的:当使用async / await检索数据时,如何在每个动作上设置ViewBag属性。
答案 0 :(得分:2)
MVC并不完全async
- 友好,尤其是过滤器。
您可以编写自己的RenderAsyncAction
扩展程序或在所有async
行动中复制代码。
或者,您可以尝试一些黑客攻击。我在我的博客why using Result
in ASP.NET can deadlock上进行了描述,但有一种解决方法:在ConfigureAwait(false)
的每个 await
上使用GetUserInfo
。
然后你可以定义一个同步包装器:
public UserInfo GetUserInfoBlocking()
{
return GetUserInfo().Result;
}
您应该可以在GetUserInfoBlocking
或OnActionExecuting
中使用RenderAction
。
请注意副作用:
async
方法每个线程使用多个请求,因此增加了可伸缩性。GetUserInfo
的所有例外情况都将包含在AggregateException
中,因此请确保您的日志记录会捕获InnerException
详细信息,否则您的日志中会出现毫无意义的错误。最好始终使用async
而不是像这样阻止。但有时MVC并没有给你一个选择(希望将来会改变)。