我使用HttpClient.PostAsync()
,回复是HttpResponseMessage
。其Content属性的类型为HttpContent
,其CopyToAsync()
方法。不幸的是,这是不可取消的。
有没有办法将回复复制到Stream
并传递CancellationToken
?
我不会被CopyToAsync()
困住!如果有解决方法,那就没问题了。就像读取几个字节一样,检查是否取消,继续阅读等等。
HttpContent.CreateContentReadStreamAsync()
方法看起来像是候选人。很遗憾,我选择的个人资料无法使用此功能。还不清楚它是否会一次性读取所有数据并浪费大量内存。
注意:我在针对WP8,Windows Store 8,.NET 4.5,Xamarin.iOS和Xamarin.Android的PCL中使用此功能
答案 0 :(得分:13)
我相信这应该有效:
public static async Task DownloadToStreamAsync(string uri, HttpContent data, Stream target, CancellationToken token)
{
using (var client = new HttpClient())
using (var response = await client.PostAsync(uri, data, token))
using (var stream = await response.Content.ReadAsStreamAsync())
{
await stream.CopyToAsync(target, 4096, token);
}
}
请注意ReadAsStreamAsync
调用CreateContentReadStreamAsync
,对于流响应只返回基础内容流而不将其缓冲到内存中。
答案 1 :(得分:2)
您无法取消不可取消的操作。请参阅How do I cancel non-cancelable async operations?。
但是,您可以允许代码流行为,就好像基础操作被取消一样WithCancellation
。
public static Task<T> WithCancellation<T>(this Task<T> task, CancellationToken cancellationToken)
{
return task.IsCompleted
? task
: task.ContinueWith(
completedTask => completedTask.GetAwaiter().GetResult(),
cancellationToken,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);
}
用法:
await httpContent.PostAsync(stream).WithCancellation(new CancellationTokenSource(1000).Token);
答案 2 :(得分:1)
HttpClient.CancelPendingRequests
将取消所有待处理的操作。我还没有验证这是否适用于CopyToAsync
。随意试试:
public static async Task CopyToAsync(
System.Net.Http.HttpClient httpClient,
System.Net.Http.HttpContent httpContent,
Stream stream, CancellationToken ct)
{
using (ct.Register(() => httpClient.CancelPendingRequests()))
{
await httpContent.CopyToAsync(stream);
}
}
[更新] 已验证:不幸的是,这不会取消HttpContent.CopyToAsync
。我保留了这个答案,因为模式本身可能对取消HttpClient
上的其他操作很有用。