如何复制HttpContent async和cancelable?

我正在使用HttpClient.PostAsync() ,响应是一个HttpResponseMessage 。 它的Content属性是HttpContent类型,它有一个CopyToAsync()方法。 不幸的是,这是不可取消的。 有没有办法将响应复制到Stream并传递CancellationToken

我没有CopyToAsync() ! 如果有解决方法,那就没问题了。 就像读取几个字节一样,检查是否取消,继续阅读等等。

HttpContent.CreateContentReadStreamAsync()方法看起来像是一个候选者。 很遗憾,我选择的个人资料无法使用此function。 还不清楚它是否会一次性读取所有数据并浪费大量内存。

注意:我在PCL中使用这个,目标是WP8,Windows Store 8,.NET 4.5,Xamarin.iOS和Xamarin.Android

我相信这应该有效:

 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 ,对于流响应, ReadAsStreamAsync返回基础内容流而不将其缓冲到内存中。

您无法取消不可取消的操作。 请参阅如何取消不可取消的异步操作? 。

但是,您可以使用WithCancellation使代码流的行为就像基础操作被取消WithCancellation

 public static Task WithCancellation(this Task 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); 

HttpClient.CancelPendingRequests应该取消所有挂起的操作。 我还没有validation是否也适用于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); } } 

[UPDATE]已经validation:遗憾的是,这并没有取消HttpContent.CopyToAsync 。 我保留了这个答案,因为模式本身可能对取消HttpClient上的其他操作很有用。