本文介绍了使用PushStreamContent从HTTPClient上传的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想从客户端计算机上将大量数据上传到Web服务器 .我跳到了PushStreamContent,所以我可以直接写到流中,因为结果的大小各不相同,而且可能很大.

I would like to upload a large amount of data to a web server from a client machine. I jumped right to PushStreamContent so I could write directly to the stream, as the results vary in size and can be rather large.

流程如下:

User runs query > Reader Ready Event Fires > Begin Upload

一旦触发ready事件,侦听器将拾取它并遍历结果集,并以多部分形式上载数据:

Once the ready event is fired, the listener picks it up and iterates over the result set, uploading the data as a multipart form:

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不会结束请求.话虽如此,写入文件将产生我希望上传的文件,因此一切都写得很好.

I think the code above would work great if I were the server, just adding stream.Close(); would finish it, however since I am the client here closing it causes an error (TaskCancelled). Waiting to read doesn't do anything either, I presume because the PushStreamContent doesn't end the request unless I explicitly close the stream. That being said, writing to a file produces exactly what I expect to be uploaded so everything writes perfectly.

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

Any ideas on what I can do here? I might be totally misusing PushStreamContent but it seems like this should be an appropriate use case.

推荐答案

因此,该解决方案起初有点令人困惑,但似乎很有意义,而且也许更重要的是,它可行:

So the solution is a little confusing at first but it seems to make sense and perhaps more importantly, it works:

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此部分的输入结束,并允许完成请求.

This works because the stream passed to the PushStreamContent method is not the actual request stream, it's a stream handled by the HttpClient, just like adding a file to a request stream. As a result, closing it signals the end of input for this part of the HttpContent and allows the request to be finalized.

这篇关于使用PushStreamContent从HTTPClient上传的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-23 15:33