在我的ASP.NET MVC應用程序中,我需要實現/重寫一些內部實體,如IModelBinder.BindModel()
,IActionFilter.OnActionExecuting()
等。這些方法調用異步方法,但顯然我無法將它們變成async Task<>
以便能夠使用關鍵字await
。如何在同步調用的任務中使HttpContext可用?
所以我寫了下面的「適配器」:
public static T GetResult<T>(Func<Task<T>> func)
{
var httpContext = HttpContext.Current;
var proxyTask = Task.Run(() =>
{
HttpContext.Current = httpContext;
return func();
});
return proxyTask.Result;
}
這讓我打電話給我的異步GetData()
同步方式:
public static async Task<Data> GetData()
{
if (isCached)
return GetCachedData();
var data = await GetOriginalData();
SetCachedData(data);
return data;
}
...
var data = GetResult(() => GetData());
好了,它的作品,所以我會叫它但是正如你所看到的,大部分時候,GetData()
同步運行,因此無條件產生一個新線程並不是很好的性能。這是竊聽我,所以我已經結束了一個不同的解決方案:
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;
}
它也可以,但問題是,既然SynchronizationContext
不再流入,存在被調用的方法沒有HttpContext
可用。
我可以通過將HttpContext.Current
合併到邏輯CallContext
中,但我仍然想知道是否有更好的方法來解決這個問題?像定製SynchronizationContext.Current.CreateCopy()
。
首先,閱讀[*我應該暴露同步包裝爲異步方法?*] [1]和[*我應該暴露異步包裝器同步的方法?*] [2] Stephan的Toub。 –
爲什麼你認爲你需要以同步的方式調用你的異步API? –
@PauloMorgado,鏈接被破壞。就像我說的,我需要實現'object IModelBinder.BindModel()','void IActionFilter.OnActionExecuting()','bool IRouteConstraint.Match()'等等,這不會給我任何選擇。 –