[英]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.