简体   繁体   中英

Run async method in overridden void

I'm currently building an ASP.NET MVC application. I'm trying to add items to the ViewBag property for all pages in my site. 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)

I know that the OnActionExecuting methods for MVC5 are not async, which is why I'm running into this issue. I need to be able to call some form of the following code to retrieve the newest items and put them into the 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.

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.

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.

There are two general methods to achieve what you wanted:

  1. Use ConfigureAwait(false) in your async library. In your case you should do it inside GetLatestPlaces() method.
  2. Call your async method in a different thread in order to not block the current context. 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 .

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. In your example, HttpContext.Current won't be available in GetLatestPlaces() .

Reason of deadlock is captured synchronized context. You can avoid this by var res = await GetLatestPlaces(3).ConfigureAwait(false);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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