C#:HttpClient,上传多个文件为MultipartFormDataContent时的文件上传进度 [英] C#: HttpClient, File upload progress when uploading multiple file as MultipartFormDataContent

查看:1247
本文介绍了C#:HttpClient,上传多个文件为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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆