在多个任务中访问HttpClient会导致"请求被取消"例外

时间:2017-02-06 17:54:21

标签: c# async-await

我正在创建一个使用REST API的应用程序。我把HTTP调用包装在这样的类中。这个类中有许多类似的方法。我为所有方法重用了相同的HttpClient实例,因为StackOverflow的答案表示它应该被重用并设计为线程安全的。

public async Task<DataType> GetData()
{
    var address = "XXX";
    var res = await Client.GetAsync(address).ConfigureAwait(false);
    var data = res.Content.ReadAsStringAsync().Result;
    return data;
}

我使用计时器定期调用API(每个计时器调用不同的API)。当只有一个计时器时,程序似乎运行良好。但是当有两个定时器时,System.Net.Http.HttpRequestException会在第二行继续发生。

System.Net.Http.HttpRequestException: 'An error occurred while sending the request.'
Inner Exception
WebException: The request was aborted: The request was canceled

内部追踪:

at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar)

外部追踪:

at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()

请求被取消是什么意思?它与Web服务器端无关,对吧?在多个线程(Task s)中调用HttpClient时是否需要处理某些事情?

更新

在使用HTTP分析器查看流量后,我发现同一个HTTP请求(应该一次只能进行一次)非常多。我在第三方UI控件的选择更改事件中启动了该任务。由于某种原因,当实际选择没有改变时,UI控件提高了选择更改事件的速度。我正在调查原因,如果这是原因,我可能不得不关闭这个问题。

更新2

我找到了一种方法来抑制那些冗余选择更改事件,现在不会发生异常。我试图删除这个问题,但警告说Stack Overflow不建议这样做,如果我继续这样做,我可能会被阻止Stack Overflow。关闭选项不符合真正的原因,所以我会离开这个。对将来有类似问题的人可能会有所帮助。

1 个答案:

答案 0 :(得分:4)

您应该调用.Result而不是

public async Task<DataType> GetData()
{
    var address = "XXX";
    var res = await Client.GetAsync(address).ConfigureAwait(false);
    var data = await res.Content.ReadAsStringAsync().ConfigureAwait(false);
    return data;
}

此处的问题是,您要卸载第一个await上的async (ConfigureAwait(false)),然后在第二个.Result上调用.Result。我无法看到应用程序的其余部分,但您可能会在qualityChanged电话上陷入僵局。

Stephan Cleary's: Article on why you shouldn't block on Async Code