简体   繁体   English

在重写的void中运行async方法

[英]Run async method in overridden void

I'm currently building an ASP.NET MVC application. 我目前正在构建一个ASP.NET MVC应用程序。 I'm trying to add items to the ViewBag property for all pages in my site. 我正在尝试将项目添加到我的网站中所有页面的ViewBag属性中。 To achieve this, I've created a base controller that all my site controllers inherit from. 为此,我创建了一个基本控制器,我的所有站点控制器都继承了该控制器。

To add to the ViewBag, I've overridden the OnActionExecuting method: protected override void OnActionExecuting(ActionExecutingContext filterContext) 要添加到ViewBag,我已经重写了OnActionExecuting方法: protected override void OnActionExecuting(ActionExecutingContext filterContext)

I know that the OnActionExecuting methods for MVC5 are not async, which is why I'm running into this issue. 我知道MVC5的OnActionExecuting方法不是异步的,这就是我遇到这个问题的原因。 I need to be able to call some form of the following code to retrieve the newest items and put them into the ViewBag: 我需要能够调用以下代码的某种形式来检索最新的项目并将它们放入ViewBag中:

IList<PlaceListItemViewModel> places = await GetLatestPlaces(3);
ViewBag.FooterLatestPlaces = places;

Using the GetLatestPlaces(3).Result just causes a deadlock, so this is not an option. 使用GetLatestPlaces(3).Result只会导致死锁,所以这不是一个选项。

Could anybody give me an option on how to achieve this. 任何人都可以给我一个如何实现这一目标的选择。 It doesn't have to be overriding the OnActionExecuting method either, if there is another way to add items to the ViewBag for every page (other than calling the code from every single action in every controller), I'm open to using that method. 它也不必重写OnActionExecuting方法,如果有另一种方法将项添加到每个页面的ViewBag(除了从每个控制器中的每个动作调用代码),我愿意使用该方法。

Unfortunately I can't the GetLatestPlaces method to be non-async, as it's using the MongoDB 2.0 driver, which is async all the way. 不幸的是,我不能将GetLatestPlaces方法设置为非异步,因为它使用MongoDB 2.0驱动程序,它始终是异步的。

There are two general methods to achieve what you wanted: 有两种通用的方法可以达到你想要的效果:

  1. Use ConfigureAwait(false) in your async library. async库中使用ConfigureAwait(false) In your case you should do it inside GetLatestPlaces() method. 在您的情况下,您应该在GetLatestPlaces()方法中执行此操作。
  2. Call your async method in a different thread in order to not block the current context. 在不同的线程中调用async方法,以便不阻止当前上下文。 So your code will look like this: 所以你的代码看起来像这样:

     IList<PlaceListItemViewModel> places = Task.Run(async () => await GetLatestPlaces(3)).Result; 

For more info see Stephen Cleary's excellent blog post . 有关更多信息,请参阅Stephen Cleary的优秀博客文章

Here is the method that allows you to call async methods in a synchronous manner, with regard to performance overhead and deadlock: 以下是允许您以同步方式调用异步方法的方法,包括性能开销和死锁:

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;
}

This way you would call 这样你就可以打电话

var places = GetResult(() => GetLatestPlaces(3));

However, beware that since current SynchronizationContext is not captured, any context that is bound to it does not flow into the task. 但是,请注意,由于未捕获当前的SynchronizationContext ,因此绑定到它的任何上下文都不会流入任务。 In your example, HttpContext.Current won't be available in GetLatestPlaces() . 在您的示例中, HttpContext.CurrentGetLatestPlaces()不可用。

Reason of deadlock is captured synchronized context. 捕获同步上下文的死锁原因。 You can avoid this by var res = await GetLatestPlaces(3).ConfigureAwait(false); 你可以通过var res = await GetLatestPlaces(3).ConfigureAwait(false);来避免这种情况var res = await GetLatestPlaces(3).ConfigureAwait(false);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM