我有一个在.NET Framework 4.7.1上运行的ASP.NET MVC 5 Web应用程序。
在控制器的操作中,我们调用服务的方法,有时会启动一个新的Task
,如下所示:
控制器:
public async Task<ActionResult> Index()
{
Info info = await this.someService.GetInformationAsync().ConfigureAwait(false);
return this.ProcessInfo( info );
}
SomeService(在static
中作为Global.asax
对象存在):
private readonly Object taskLock = new Object();
private Task errorCheckerTask;
public Task<Info> GetInformationAsync()
{
try
{
...
}
catch( Exception ex )
{
this.StartErrorChecker();
}
return null;
}
private void StartErrorChecker()
{
lock( this.taskLock )
{
if( this.errorCheckerTask == null || this.errorCheckerTask.Status >= TaskStatus.RanToCompletion )
{
this.errorCheckerTask = this.BeginErrorCheckerAsync( CancellationToken.None );
}
}
}
private async Task BeginErrorCheckerAsync( CancellationToken ct )
{
while( !ct.IsCancellationRequested )
{
Boolean ok = await DoStuff();
if( ok ) return;
await Task.Delay( 30 * 1000 ).ConfigureAwait(false);
}
}
第一次启动BeginErrorCheckerAsync
任务后,情况似乎没问题 - 但是当BeginErrorCheckerAsync
第二次运行时,Visual Studio的Output
窗口会报告一堆线程结束然后网络应用程序停止响应任何新的HTTP请求 - 所有浏览器只是说他们在发送请求后正在等待响应。
我按下了Break按钮,Visual Studio Threads窗口只显示了一些运行的线程,其中没有一个线程在任何堆栈跟踪中都有任何用户代码。
重要的是,除了有关线程的消息之外,没有引发第一次机会异常或在“输出”窗口中显示任何异常输出:
线程0x5440已退出,代码为0(0x0)。 线程0x547c已退出,代码为0(0x0)。 线程0x5450已退出,代码为0(0x0)。 线程0x5474已退出,代码为0(0x0)。
我假设我没有在ASP.NET MVC中发现错误 - 但我不明白我对Tasks / async
/ await
的使用如何使ASP.NET陷入僵局(假设这是问题)。我注意到我的代码中没有任何地方可以调用task.Result
或task.Wait()
来排除传统形式的async / await死锁,而且无论如何都没有.NET代码中的线程堆栈跟踪。
答案 0 :(得分:0)
您无法在控制器操作方法上调用ConfigureAwait(false)
,因为它们必须在同步上下文中运行。