簡體   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