繁体   English   中英

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

[英]ASP.NET Web API async controller method and deadlock

请帮助我了解为什么此代码会导致死锁? 我有一个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.SendAsync的实现。 如果它在当前线程上获得了锁定,则为时已晚。 毕竟,也不建议在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()方法中的async关键字。

    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;
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM