c# - 传入一个已经取消的 CancellationToken 导致 HttpClient 挂起

标签 c# task-parallel-library dotnet-httpclient cancellationtokensource

我想使用 CancellationToken 取消对 HttpClient.PostAsJsonAsync 的调用。但是,通过以下设置,对 PostAsJsonAsync 的调用无限期挂起(我让它运行了几分钟)。

CancellationTokenSource source = new CancellationTokenSource();
source.Cancel();
HttpClient client = new HttpClient();

try
{
    var task = client.PostAsJsonAsync<MyObject>("http://server-address.com",
        new MyObject(), source.Token);

    task.Wait();
}
catch (Exception ex)
{
    //Never gets hit.
}

请注意,我正在传递一个已经取消的 CancellationTokenSource - 如果我使用 Task.Delay 取消 token 并延迟很短,我会遇到同样的问题。

我意识到我可以简单地检查 token 是否在调用之前被取消,但即便如此,如果 token 在短暂延迟后被取消,我也会遇到同样的问题,即它在方法调用之前没有被取消,而是变成了不久之后。

所以我的问题是,是什么原因造成的,我该怎么做才能解决/修复它?

编辑

对于那些寻求解决方法的人,受@Darrel Miller 的回答启发,我提出了以下扩展方法:

public static async Task<HttpResponseMessage> PostAsJsonAsync2<T>(this HttpClient client, string requestUri, T value, CancellationToken token)
{
    var content = new ObjectContent(typeof(T), value, new JsonMediaTypeFormatter());
    await content.LoadIntoBufferAsync();

    return await client.PostAsync(requestUri, content, token);
}

最佳答案

这肯定是你遇到的一个错误你可以通过自己构造 HttpContent/ObjectContent 对象来解决它,就像这样。

CancellationTokenSource source = new CancellationTokenSource();
source.Cancel();
HttpClient client = new HttpClient();

var content = new ObjectContent(typeof (MyObject), new MyObject(), new JsonMediaTypeFormatter());
content.LoadIntoBufferAsync().Wait();
try
{
    var task = client.PostAsync("http://server-address.com",content, source.Token);

    task.Wait();
}
catch (Exception ex)
{
    //This will get hit now with an AggregateException containing a TaskCancelledException.
}

调用 content.LoadIntoBufferAsync 强制反序列化发生在 PostAsync 之前,似乎可以避免死锁。

关于c# - 传入一个已经取消的 CancellationToken 导致 HttpClient 挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23075255/

相关文章:

c# - 在 HttpClientHandler 可移植类库 (PCL) 中设置代理时找不到方法

C#:HttpClient,服务器违反了协议(protocol)。部分=响应状态行

c# - 重新设置单例httpclient的证书(Reconfiguring IHttpclientFactory?)

c# - 如何从 xsd 创建 wsdl

c# - 何时处置 CancellationTokenSource?

c# - MongoDB .NET 驱动程序按时间范围分组

c# - TaskScheduler.Default 不总是保证任务将在池线程上执行吗?

c# - 创建具有较长延迟的任务是否可以接受?

c# - 如何在 C# 中的站点的 Web 请求之间引入延迟?

c# - Json在C#中反序列化