[英]Run async method in overridden void
我目前正在构建一个ASP.NET MVC应用程序。 我正在尝试将项目添加到我的网站中所有页面的ViewBag属性中。 为此,我创建了一个基本控制器,我的所有站点控制器都继承了该控制器。
要添加到ViewBag,我已经重写了OnActionExecuting方法: protected override void OnActionExecuting(ActionExecutingContext filterContext)
我知道MVC5的OnActionExecuting方法不是异步的,这就是我遇到这个问题的原因。 我需要能够调用以下代码的某种形式来检索最新的项目并将它们放入ViewBag中:
IList<PlaceListItemViewModel> places = await GetLatestPlaces(3);
ViewBag.FooterLatestPlaces = places;
使用GetLatestPlaces(3).Result
只会导致死锁,所以这不是一个选项。
任何人都可以给我一个如何实现这一目标的选择。 它也不必重写OnActionExecuting方法,如果有另一种方法将项添加到每个页面的ViewBag(除了从每个控制器中的每个动作调用代码),我愿意使用该方法。
不幸的是,我不能将GetLatestPlaces方法设置为非异步,因为它使用MongoDB 2.0驱动程序,它始终是异步的。
有两种通用的方法可以达到你想要的效果:
async
库中使用ConfigureAwait(false)
。 在您的情况下,您应该在GetLatestPlaces()
方法中执行此操作。 在不同的线程中调用async
方法,以便不阻止当前上下文。 所以你的代码看起来像这样:
IList<PlaceListItemViewModel> places = Task.Run(async () => await GetLatestPlaces(3)).Result;
有关更多信息,请参阅Stephen Cleary的优秀博客文章 。
以下是允许您以同步方式调用异步方法的方法,包括性能开销和死锁:
public static T GetResult<T>(Func<Task<T>> func)
{
var syncContext = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(null);
var task = func();
SynchronizationContext.SetSynchronizationContext(syncContext);
return task.Result;
}
这样你就可以打电话
var places = GetResult(() => GetLatestPlaces(3));
但是,请注意,由于未捕获当前的SynchronizationContext
,因此绑定到它的任何上下文都不会流入任务。 在您的示例中, HttpContext.Current
在GetLatestPlaces()
不可用。
捕获同步上下文的死锁原因。 你可以通过var res = await GetLatestPlaces(3).ConfigureAwait(false);
来避免这种情况var res = await GetLatestPlaces(3).ConfigureAwait(false);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.