还有另一个HttpClient /异步死锁

时间:2018-03-06 03:02:50

标签: c# wpf async-await dotnet-httpclient

我已经在这上面敲了几个小时,我已经把手举到空中了。据我所知,我遇到了围绕HttpClient和异步的死锁。

目标是让一系列不相关的帖子快速连续发布,等待所有人完成,然后从结果集构建一个文档。该程序具有WPF UI,这由按钮触发:

private async void Generate_Suite_BTN_Click(object sender, RoutedEventArgs e)
{
    var suiteBuilder = new SuiteBuilder();
    await Task.Run(() => suiteBuilder.worker_Run());
}

触发了worker_Run(),它有一些切换逻辑,并最终导致命中具有Parrallel.Foreach的SendFiles(),因为发送文件不需要是顺序的,并且是彼此无关:

private bool SendFiles()
{
    var result = Parallel.ForEach(_InfoCollection, SendFile);
    return result.IsCompleted;
}

在SendFile()中等待每个(并行)中的每一个,它也有一些切换逻辑,基于我们发送的内容,但最终归结为:

var result = await Client.SendMessage ( vars );
results.Add(result.MessageId, result.StatusCode, result.HttpReason);

这是SendMessage()中的HttpClient部分:

public async Task<Result> SendMessage(vars)
{
    var soapResponse = new XmlDocument();
    try
    {
        Client.DefaultRequestHeaders.Add("SOAPAction", soapAction);
        Client.Timeout = TimeSpan.FromSeconds(Timeout);
        var content = new StringContent(soapRequest, Encoding.UTF8, contentType);
        var post =  await Client.PostAsync(url, content).ConfigureAwait(false);
        var response = post.Content;
        result.StatusCode = post.StatusCode;
        result.HttpReason = post.ReasonPhrase;
        var sResponse = await response.ReadAsStringAsync().ConfigureAwait(false);
        soapResponse.Load(sResponse);
    }
    catch (Exception ex)
    {
        //Catch logic
    }
}

我可以看到请求和响应与Fiddler来回传递,但是我遇到了逐行调试的问题,因为一旦我点击PostAsync,VS就会翻转并继续一直到程序结束时,跳过所有断点。同时,请求超时后会出现TaskCanceledException,很久之后应该完成的代码已经完成。

我看了几十个问题&amp;关于SO和其他地方的答案,但他们并没有完全帮助找到问题。大多数人似乎都围绕着#34; .ConfigureAwait(false)&#34;在异步调用上,但它似乎没有任何影响。

1 个答案:

答案 0 :(得分:2)

所以,在评论中@JSteward的帮助下,他指出asyncParrallel.ForEach不太适合一起工作,因为void的回复类型在处理时应该避免使用异步。

他建议我只使用Async,从顶部(按钮点击)到底部(消息发送),然后就可以了。感谢他的指导。

此链接有助于解释原因:Async/Await - Best Practices in Asynchronous Programming

SendFiles最终看起来像这样:

private async Task<bool> SendFiles()
{
    var result = _InfoCollection.Select(SendFile);
    await Task.WhenAll(result).ConfigureAwait(false);
    return true;
}

所有其他方法都asyncawaitsTaskTask<T>的返回类型。