如何复制HttpContent async和cancelable?

时间:2014-01-03 11:22:39

标签: c# .net xamarin async-await dotnet-httpclient

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

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

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

注意:我在针对WP8,Windows Store 8,.NET 4.5,Xamarin.iOS和Xamarin.Android的PCL中使用此功能

3 个答案:

答案 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上的其他操作很有用。