请帮助我理解为什么这段代码会导致死锁? 我有一个 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;
}