2015-11-20 60 views
1

编辑:我现在通过简单地将按钮点击处理程序标记为async void并等待任务来解决问题。我认为WebForms无法以任何方式处理异步,除非与RegisterAsyncTask一起使用。虽然这解决了我的问题,但我仍然对代码处于死锁之下的原因感兴趣,因为它违背了我对当前C#代码异步工作的理解,所以仍然赞赏答案。ASP.NET死锁尽管ConfigureAwait(false)

我有一个服务公开了一个异步方法,它向一些api发送一个请求。此方法在webforms代码隐藏中消耗。我知道ASP.NET只允许一次执行一个线程,因此调用Task.Wait()会导致死锁,因为等待处理的任务在上下文线程被阻止时无法在完成时恢复执行。

但是,我的理解(从读this blog),在等待的任务上调用ConfigureAwait(false)会导致任务在线程池线程上运行,因此可以恢复上下文线程上的执行。尽管如此,我仍然遇到了来自下面代码的僵局。为什么是这样?

protected void Activate(object sender, CommandEventArgs e) 
{ 
    var someID = int.Parse((string) e.CommandArgument); 
    DoAsyncThingWithID(someID).Wait(); 
} 

private async Task DoAsyncThingWithID(int ID) 
{ 
    try 
    { 
     await new SomeService() 
      .DoSomeAsyncWork(ID) 
      .ConfigureAwait(false); 
    } 
    catch (AppropriateException e) 
    { 
     DealWithIt(); 
    } 
} 

值得注意的是:DoSomeAsyncWork(int)在它下面有更多的异步方法。在底部有一个API包装对象(负责发送HTTP请求)的方法不是异步,但调用Task.Run(() => api.SendThingy());

这可能是问题吗?

+0

发布你的搜索答案并收听。 –

回答

5

但是,由于它是我的理解(从阅读这个博客),其对期待已久的任务调用ConfigureAwait(假)将导致任务上的线程池线程,而不是运行,因此执行上下文线程可以恢复。

其实用ConfigureAwait(false)延续不关心它在执行什么情况下目前的方法 - 与绝大多数的时间,这意味着它会继续一个线程池线程。

因此,DoSomeAsyncWork仍然会在ASP.NET上下文中运行。出于这个原因,只有一个ConfigureAwait(false)是不够的。您必须确保DoSomeAsyncWork也使用ConfigureAwait(false)以及它调用的所有异步方法以及它们调用的所有异步方法等,包括Microsoft或第三方库方法。

这就是为什么我建议不要阻止开始。如果你绝对有到,ConfigureAwait(false)黑客只是试图绕过它的其中一种方法。

+0

我明白了,是的,这确实使得依靠下面所有人调用该方法都是非常不可取的。我想你可以让它成为你的团队的标准,但是你仍然无法在第三方库中强制执行它。幸运的是,他们实际上在webforms中实现了一些异步支持,因为我们有一些遗留项目在其中。 – kai

0

我现在只需将按钮点击处理程序标记为async void并等待任务即可解决问题。我认为WebForms不能以任何方式处理async,除非与RegisterAsyncTask一起使用。虽然这解决了我的问题,但我仍然对原始代码为什么死锁感兴趣,因为它违背了我当前对异步C#代码工作方式的理解,因此还有进一步的答案。