C#:HttpClient,上传多个文件为MultipartFormDataContent时的文件上传进度 [英] C#: HttpClient, File upload progress when uploading multiple file as MultipartFormDataContent
问题描述
我使用这段代码上传了多个文件,效果很好。它使用modernhttpclient库。
public async Task< string> PostImages(int platform,string url,List< byte []> imageList)
{
try {
int count = 1;
var requestContent = new MultipartFormDataContent();
foreach(var imageList in imageList){
var imageContent = new ByteArrayContent(image);
imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse(image / jpeg);
requestContent.Add(imageContent,image+ count,image.jpg);
count ++;
}
var cookieHandler = new NativeCookieHandler();
var messageHandler = new NativeMessageHandler(false,false,cookieHandler);
cookieHandler.SetCookies(cookies);
using(var client = new HttpClient(messageHandler)){
client.DefaultRequestHeaders.TryAddWithoutValidation(User-Agent,GetUserAgent(platform));
using(var r = await client.PostAsync(url,requestContent)){
string result = await r.Content.ReadAsStringAsync();
System.Diagnostics.Debug.WriteLine(PostAsync:+ result);
返回结果;
$ b $ catch(Exception e){
System.Diagnostics.Debug.WriteLine(e.Message);
返回null;
$ / code $ / pre
现在我需要上传文件时的进度。我在谷歌搜索,发现我需要使用ProgressStreamContent
https://github.com/paulcbetts/ModernHttpClient/issues/80
由于ProgressStreamContent包含一个构造函数,它接受一个流,我转换MultipartFormDataContent将在其构造函数中进行流式处理和使用。但是,它不工作。上传失败。我认为它是因为它是所有文件的流,这是不是我的后端预期。
公共异步任务< ;串GT; PostImages(int platform,string url,List< byte []> imageList)
{
try {
int count = 1;
var requestContent = new MultipartFormDataContent();
//这里你可以指定边界如果你需要--- ^
foreach(var imageList in imageList){
var imageContent = new ByteArrayContent(image);
imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse(image / jpeg);
requestContent.Add(imageContent,image+ count,image.jpg);
count ++;
}
var cookieHandler = new NativeCookieHandler();
var messageHandler = new NativeMessageHandler(false,false,cookieHandler);
cookieHandler.SetCookies(RestApiPaths.cookies);
var stream = await requestContent.ReadAsStreamAsync();
var client = new HttpClient(messageHandler);
client.DefaultRequestHeaders.TryAddWithoutValidation(User-Agent,RestApiPaths.GetUserAgent(platform));
var request = new HttpRequestMessage(HttpMethod.Post,url);
var progressContent = new ProgressStreamContent(stream,4096);
progressContent.Progress =(bytes,totalBytes,totalBytesExpected)=> {
Console.WriteLine(上传{0} / {1},totalBytes,totalBytesExpected);
};
request.Content = progressContent;
var response = await client.SendAsync(request);
string result = await response.Content.ReadAsStringAsync();
System.Diagnostics.Debug.WriteLine(PostAsync:+ result);
返回结果;
catch(Exception e){
System.Diagnostics.Debug.WriteLine(e.Message);
返回null;
$ b $ p
$ b我应该在这里做些什么来得到这个工作?任何帮助表示赞赏解决方案我有一个ProgressableStreamContent的工作版本。请注意,我在构造函数中添加了头文件,这是原始ProgressStreamContent中的一个错误,它不会添加头文件!
内部类ProgressableStreamContent:HttpContent
{
///< summary>
///让我们保留20kb的缓冲
///< / summary>
private const int defaultBufferSize = 5 * 4096;
私人HttpContent内容;
private int bufferSize;
//私人bool contentConsumed;
private action< long,long>进展;
$ b $ public ProgressableStreamContent(HttpContent content,Action< long,long> progress):this(content,defaultBufferSize,progress){}
$ b $ public ProgressableStreamContent(HttpContent content,int bufferSize, (内容== null)
{
throw new ArgumentNullException(content);
if(bufferSize< = 0)
{
throw new ArgumentOutOfRangeException(bufferSize);
}
this.content = content;
this.bufferSize = bufferSize;
this.progress =进度;
foreach(content.Headers中的var h){
this.Headers.Add(h.Key,h.Value);
$ b保护覆盖任务SerializeToStreamAsync(Stream stream,TransportContext上下文)
{
return Task.Run(async() =>
{
var buffer = new Byte [this.bufferSize];
long size;
TryComputeLength(out size);
var uploaded = 0;
使用(var sinput = await content.ReadAsStreamAsync())
(
while(true)
{
var length = sinput。读取(缓冲区,0,buffer.Length);
if(length <= 0)break;
//downloader.Uploaded =上传+ =长度;
已上传+ =长度;
进度?.Invoke(上传,大小);
//System.Diagnostics.Debug.WriteLine($Bytes sent {uploaded} of {size});
stream.Write(buffer,0,le NGTH);
stream.Flush();
}
}
stream.Flush();
});
protected override bool TryComputeLength(out long length)
{
length = content.Headers.ContentLength.GetValueOrDefault();
返回true; (bool处置)
{
如果(处理)
{
content.Dispose();
保护覆盖无效处置
}
base.Dispose(disposing);
$ p
$ b 还要注意,它期望HttpContent,
$ p $ var progressContent = new ProgressableStreamContent(
requestContent,
4096,
(sent,total)=> {
Console.WriteLine(上传{0} / {1},发送,总计);
});
I'm using this code to upload multiple files and it working very well. It uses modernhttpclient library.
public async Task<string> PostImages (int platform, string url, List<byte []> imageList)
{
try {
int count = 1;
var requestContent = new MultipartFormDataContent ();
foreach (var image in imageList) {
var imageContent = new ByteArrayContent (image);
imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse ("image/jpeg");
requestContent.Add (imageContent, "image" + count, "image.jpg");
count++;
}
var cookieHandler = new NativeCookieHandler ();
var messageHandler = new NativeMessageHandler (false, false, cookieHandler);
cookieHandler.SetCookies (cookies);
using (var client = new HttpClient (messageHandler)) {
client.DefaultRequestHeaders.TryAddWithoutValidation ("User-Agent", GetUserAgent (platform));
using (var r = await client.PostAsync (url, requestContent)) {
string result = await r.Content.ReadAsStringAsync ();
System.Diagnostics.Debug.WriteLine ("PostAsync: " + result);
return result;
}
}
} catch (Exception e) {
System.Diagnostics.Debug.WriteLine (e.Message);
return null;
}
}
Now I need the progress when uploading the files. I searched in google and found I need to use ProgressStreamContent
https://github.com/paulcbetts/ModernHttpClient/issues/80
Since ProgressStreamContent contains a constructor that takes a stream, I converted the MultipartFormDataContent to stream and used it in its constructor. But, its not working. Upload fails. I think its because it is a stream of all the files together which is not what my back end is expecting.
public async Task<string> PostImages (int platform, string url, List<byte []> imageList)
{
try {
int count = 1;
var requestContent = new MultipartFormDataContent ();
// here you can specify boundary if you need---^
foreach (var image in imageList) {
var imageContent = new ByteArrayContent (image);
imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse ("image/jpeg");
requestContent.Add (imageContent, "image" + count, "image.jpg");
count++;
}
var cookieHandler = new NativeCookieHandler ();
var messageHandler = new NativeMessageHandler (false, false, cookieHandler);
cookieHandler.SetCookies (RestApiPaths.cookies);
var stream = await requestContent.ReadAsStreamAsync ();
var client = new HttpClient (messageHandler);
client.DefaultRequestHeaders.TryAddWithoutValidation ("User-Agent", RestApiPaths.GetUserAgent (platform));
var request = new HttpRequestMessage (HttpMethod.Post, url);
var progressContent = new ProgressStreamContent (stream, 4096);
progressContent.Progress = (bytes, totalBytes, totalBytesExpected) => {
Console.WriteLine ("Uploading {0}/{1}", totalBytes, totalBytesExpected);
};
request.Content = progressContent;
var response = await client.SendAsync (request);
string result = await response.Content.ReadAsStringAsync ();
System.Diagnostics.Debug.WriteLine ("PostAsync: " + result);
return result;
} catch (Exception e) {
System.Diagnostics.Debug.WriteLine (e.Message);
return null;
}
}
What should I do here to get this working? Any help is appreciated
解决方案 I have a working version of ProgressableStreamContent. Please note, I am adding headers in the constructor, this is a bug in original ProgressStreamContent that it does not add headers !!
internal class ProgressableStreamContent : HttpContent
{
/// <summary>
/// Lets keep buffer of 20kb
/// </summary>
private const int defaultBufferSize = 5*4096;
private HttpContent content;
private int bufferSize;
//private bool contentConsumed;
private Action<long,long> progress;
public ProgressableStreamContent(HttpContent content, Action<long,long> progress) : this(content, defaultBufferSize, progress) { }
public ProgressableStreamContent(HttpContent content, int bufferSize, Action<long,long> progress)
{
if (content == null)
{
throw new ArgumentNullException("content");
}
if (bufferSize <= 0)
{
throw new ArgumentOutOfRangeException("bufferSize");
}
this.content = content;
this.bufferSize = bufferSize;
this.progress = progress;
foreach (var h in content.Headers) {
this.Headers.Add(h.Key,h.Value);
}
}
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
return Task.Run(async () =>
{
var buffer = new Byte[this.bufferSize];
long size;
TryComputeLength(out size);
var uploaded = 0;
using (var sinput = await content.ReadAsStreamAsync())
{
while (true)
{
var length = sinput.Read(buffer, 0, buffer.Length);
if (length <= 0) break;
//downloader.Uploaded = uploaded += length;
uploaded += length;
progress?.Invoke(uploaded, size);
//System.Diagnostics.Debug.WriteLine($"Bytes sent {uploaded} of {size}");
stream.Write(buffer, 0, length);
stream.Flush();
}
}
stream.Flush();
});
}
protected override bool TryComputeLength(out long length)
{
length = content.Headers.ContentLength.GetValueOrDefault();
return true;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
content.Dispose();
}
base.Dispose(disposing);
}
}
Also note, it expects HttpContent, not stream.
This is how you can use it.
var progressContent = new ProgressableStreamContent (
requestContent,
4096,
(sent,total) => {
Console.WriteLine ("Uploading {0}/{1}", sent, total);
});
这篇关于C#:HttpClient,上传多个文件为MultipartFormDataContent时的文件上传进度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!