【发布时间】:2018-06-22 22:06:16
【问题描述】:
在我的 Asp.Net WebApi 控制器(框架版本 4.6.1)中,我有以下代码:
[Route("async_test_2")]
public async Task<IHttpActionResult> AsyncTest2()
{
TelemetryDebugWriter.IsTracingDisabled = true;
var aspNetContext = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext()); //set context while calling AsyncMethod
var task = AsyncMethod();
SynchronizationContext.SetSynchronizationContext(aspNetContext); //Restore AspNet context before awaiting
DebugContext("Before outer await");
await Task.WhenAll(new Task[] { task });
DebugContext("After outer await");
return Ok();
}
private async Task AsyncMethod()
{
DebugContext("Before inner await");
await Task.Delay(2000);
DebugContext("After inner await");
}
private void DebugContext(string location)
{
System.Diagnostics.Debug.WriteLine(location + " --- SyncContext: " + (SynchronizationContext.Current?.ToString() ?? "null") + "; ManagedThreadId: " + Thread.CurrentThread.ManagedThreadId);
}
调试输出为:
Before inner await --- SyncContext: System.Threading.SynchronizationContext; ManagedThreadId: 6
Before outer await --- SyncContext: System.Web.AspNetSynchronizationContext; ManagedThreadId: 6
After inner await --- SyncContext: null; ManagedThreadId: 5
After outer await --- SyncContext: System.Web.AspNetSynchronizationContext; ManagedThreadId: 6
为什么延续“内部等待之后”的 SynchronizationContext 为空?如果我只是删除对 SetSynchronizationContext 的调用和恢复它的调用(即不修改上下文,保留默认的 AspNetSynchronizationContext),那么上下文在任何调试输出中都不为空。
Before inner await --- SyncContext: System.Web.AspNetSynchronizationContext; ManagedThreadId: 7
Before outer await --- SyncContext: System.Web.AspNetSynchronizationContext; ManagedThreadId: 7
After inner await --- SyncContext: System.Web.AspNetSynchronizationContext; ManagedThreadId: 8
After outer await --- SyncContext: System.Web.AspNetSynchronizationContext; ManagedThreadId: 8
在内部 await 之后添加“ConfigureAwait(false)”将导致上下文在延续中按预期为空。
Before inner await --- SyncContext: System.Web.AspNetSynchronizationContext; ManagedThreadId: 7
Before outer await --- SyncContext: System.Web.AspNetSynchronizationContext; ManagedThreadId: 7
After inner await --- SyncContext: null; ManagedThreadId: 7
After outer await --- SyncContext: System.Web.AspNetSynchronizationContext; ManagedThreadId: 8
因此,当 AspNetSynchronizationContext 处于活动状态时,它会按预期工作,但在默认 SynchronizationContext 处于活动状态时则不会。在这种情况下,无论是否调用 ConfigureAwait(false),它在继续中始终为 null。
【问题讨论】:
-
你运行的是什么版本的 .net ?
-
Web 应用程序配置为使用 .NET Framework v4.6.1。
-
这让我很困惑,任何人都应该从 sn-p 获得这个问题的重现。使用 Debug > Windows > Threads 窗口来验证假设,确保您仍在预期的线程上。
-
好的,我会简单地为你提供一个完整的实现和简单的调试输出,你可以在黑色的 ASP.NET 应用程序中自己运行。
-
在 Visual Studio 2017 中创建一个新的空 MVC 项目,并将
HomeController.vb替换为 this code,确实给了我您所看到的相同结果。我仍在尝试围绕 async / await 的更精细点展开思考,所以我无法真正说明为什么会发生这种情况。
标签: async-await synchronizationcontext