【问题标题】:Using PushStreamContent to upload from an HTTPClient使用 PushStreamContent 从 HTTPClient 上传
【发布时间】:2016-02-09 03:20:51
【问题描述】:

我想将大量数据客户端机器上传到网络服务器。我直接跳到 PushStreamContent,这样我就可以直接写入流,因为结果的大小各不相同,而且可能相当大。

流程如下:

User runs query > Reader Ready Event Fires > Begin Upload

一旦 ready 事件被触发,监听器就会拾取它并迭代结果集,将数据作为多部分表单上传:

Console.WriteLine("Query ready, uploading");
        byte[] buffer = new byte[1024], form = new byte[200];
        int offset = 0, byteCount = 0;
        StringBuilder rowBuilder = new StringBuilder();
        string builderS;
        var content = new PushStreamContent(async (stream, httpContent, transportContext) =>
        //using (System.IO.Stream stream = new System.IO.FileStream("test.txt", System.IO.FileMode.OpenOrCreate))
        {
            int bytes = 0;
            string boundary = createFormBoundary();
            httpContent.Headers.Remove("Content-Type");
            httpContent.Headers.TryAddWithoutValidation("Content-Type", "multipart/form-data; boundary=" + boundary);
            await stream.WriteAsync(form, 0, form.Length);
            form = System.Text.Encoding.UTF8.GetBytes(createFormElement(boundary, "file"));
            await stream.WriteAsync(form, 0, form.Length);
            await Task.Run(async () =>
            {
                foreach (var row in rows)
                {
                    for (int i = 0; i < row.Length; i++)
                    {
                        rowBuilder.Append(row[i].Value);
                        if (i + 1 < row.Length)
                            rowBuilder.Append(',');
                        else
                        {
                            rowBuilder.Append("\r\n");
                        }
                    }
                    builderS = rowBuilder.ToString();
                    rowBuilder.Clear();
                    byteCount = System.Text.Encoding.UTF8.GetByteCount(builderS);
                    bytes += byteCount;
                    if (offset + byteCount > buffer.Length)
                    {
                        await stream.WriteAsync(buffer, 0, offset);
                        offset = 0;
                        if (byteCount > buffer.Length)
                        {
                            System.Diagnostics.Debug.WriteLine("Expanding buffer to {0} bytes", byteCount);
                            buffer = new byte[byteCount];
                        }
                    }
                    offset += System.Text.Encoding.UTF8.GetBytes(builderS, 0, builderS.Length, buffer, offset);
                }
            });
            await stream.WriteAsync(buffer, 0, offset);
            form = System.Text.Encoding.UTF8.GetBytes(boundary);
            await stream.WriteAsync(form, 0, form.Length);
            await stream.FlushAsync(); //pretty sure this does nothing
            System.Diagnostics.Debug.WriteLine("Wrote {0}.{1} megabytes of data", bytes / 1000000, bytes % 1000000);

如果我是服务器,我认为上面的代码会很好用,只需添加 stream.Close(); 即可完成它,但是由于我是这里的客户端,因此关闭它会导致错误 (TaskCancelled)。等待读取也不做任何事情,我认为是因为 PushStreamContent 不会结束请求,除非我明确关闭流。话虽如此,写入文件会产生我期望上传的内容,因此一切都可以完美写入。

关于我可以在这里做什么的任何想法?我可能完全滥用了PushStreamContent,但似乎这应该是一个合适的用例。

【问题讨论】:

  • 这段代码是如何被调用的?
  • @JonathanAmend 它由作为单独类的一部分的委托事件触发。该事件仅在阅读器准备好并拥有数据后触发,并提供一个 IEnumerable (GetRows()),然后可用于读取结果。方法本身也是异步的
  • AFAIK stream.Close() 是告诉对方他们得到数据的正确方法。您从哪里得到 TaskCancelled 异常?
  • @JonathanAmend 当我打电话给httpclient.putAsync("url", content); 抱歉,帖子中没有出现任务取消。它仅在我关闭流时发生,我认为原因是因为远程服务器没有响应。读入虽然没有任何作用,所以我需要找到某种方式来表明我实际上已经完成了写入并且服务器应该响应。我认为...
  • 你把stream.Close()放在哪里?它应该代替 stream.FlushAsync()。

标签: c# http file-upload async-await dotnet-httpclient


【解决方案1】:

所以这个解决方案一开始有点令人困惑,但它似乎是有道理的,也许更重要的是,它有效:

using(var content = new MultipartFormDataContent()) 
{
  var pushContent = new PushStreamContent(async (stream, httpContent, transportContext) =>
  { 
    //do the stream writing stuff
    stream.Close();
  });
  content.add(pushContent);
  //post, put, etc. content here
}

之所以有效,是因为传递给PushStreamContent 方法的流不是实际的请求流,而是由HttpClient 处理的流,就像向请求流中添加文件一样。因此,关闭它表示 HttpContent 的这部分输入的结束,并允许最终确定请求。

【讨论】:

  • 感谢分享!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-10
  • 1970-01-01
  • 1970-01-01
  • 2017-11-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多