ASP.NET Web API 异步控制器方法和死锁



请帮助我理解为什么这段代码会导致死锁? 我有一个 asp.net Web api 应用程序,我试图使一些控制器方法异步。


[HttpPost]
[Authentication]
public async Task<SomeDTO> PostSomething([FromBody] SomeDTO someDTO)
{
return await _service.DoSomething(someDTO);
}

这就是所谓的服务方法的外观:


public async Task<SomeDTO> DoSomething(SomeDTO someDTO)
{
...
var someTask = Task.Run(() => 
{
var entity = new SomeEntity(someDTO);
return _repository.Create(entity);
});
...
var result = await someTask;
...
}

还有一些全局处理程序,可以打印对控制台的响应。


public class AppGlobalHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var resp = base.SendAsync(request, cancellationToken);
Debug.WriteLine($"Response:{request.RequestUri}{Environment.NewLine}{resp?.ConfigureAwait(false).GetAwaiter().GetResult()?.Content?.ReadAsStringAsync().ConfigureAwait(false).GetAwaiter().GetResult()}");
return resp;
}
}

看起来像 ConfigureAwait(false(。GetAwaiter((。GetResult(( 阻止调用线程,但我认为 ConfigureAwait(false( 应该避免这种情况,不是吗?

ConfigureAwait(false( 在这里不会帮助你,因为它必须在调用堆栈中一直向下(在此处查看更多内容(,而不是在您同步等待的位置,即它取决于 base 的实现。发送异步。如果它在当前线程上获得了锁,那么对它做点什么为时已晚。毕竟,也不建议 ASP.net 管道中继续在其他线程上响应(请参阅此处的讨论并在此处发布(。

最后,在异步上下文中同步等待始终是一个高风险的想法。 如果您需要阅读内容,为什么不这样做:

public class AppGlobalHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var resp = await base.SendAsync(request, cancellationToken);
var content = resp?.Content != null 
? (await resp.Content.ReadAsStringAsync()) 
: string.Empty; 
Debug.WriteLine($"Response:{request.RequestUri}{Environment.NewLine}{content}");
return resp;
}
}

我认为您忽略了 Task.Run(( 方法中的异步关键字。

public async Task<SomeDTO> DoSomething(SomeDTO someDTO)
{ 
var someTask = Task.Run( async () => //simply add this for async run 
{
var entity = new SomeEntity(someDTO);
return _repository.Create(entity);
}); 
var result = await someTask;
}

最新更新