使用 PushStreamContent 从 HTTPClient 上传
Using PushStreamContent to upload from an HTTPClient
我想将大量数据从 客户端计算机上传到网络服务器。我直接跳到 PushStreamContent,这样我就可以直接写入流,因为结果的大小各不相同,而且可能相当大。
流程如下:
User runs query > Reader Ready Event Fires > Begin Upload
触发就绪事件后,侦听器将其拾取并遍历结果集,以多部分形式上传数据:
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
但看起来 应该是 一个合适的用例。
所以解决方案一开始有点令人困惑,但它似乎有道理,也许更重要的是,它有效:
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
这部分的输入结束,并允许完成请求。
我想将大量数据从 客户端计算机上传到网络服务器。我直接跳到 PushStreamContent,这样我就可以直接写入流,因为结果的大小各不相同,而且可能相当大。
流程如下:
User runs query > Reader Ready Event Fires > Begin Upload
触发就绪事件后,侦听器将其拾取并遍历结果集,以多部分形式上传数据:
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
但看起来 应该是 一个合适的用例。
所以解决方案一开始有点令人困惑,但它似乎有道理,也许更重要的是,它有效:
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
这部分的输入结束,并允许完成请求。