пользовательский ProgressableStreamContent не работает - PullRequest
0 голосов
/ 22 марта 2020

Привет в соответствии с: https://gist.github.com/HirbodBehnam/272aa5e4b82c2fb05583d095f2224861

Я реализовал это:

Мой звонок:

public async Task<string> UploadFiles(FileInfo fileInfo)
    {
        string res = null; 

        using (var client = new HttpClient())
        using (var multiForm = new MultipartFormDataContent())
        {
            client.Timeout = TimeSpan.FromMinutes(5); // You may need this if you are uploading a big file

            var file = new ProgressableStreamContent(new StreamContent(File.OpenRead(fileInfo.FullName))
                , (sent, total) => {
                    //Console.SetCursorPosition(1, 0); // Remove last line
                    Console.WriteLine("\bUploading " + ((float)sent / total) * 100f);
                });

            multiForm.Add(file, fileInfo.Name, fileInfo.Name); // Add the file

            var uploadServiceBaseAdress = "http://10.0.2.2:44560/PostFiles/";

            var response = await client.PostAsync(uploadServiceBaseAdress, multiForm);
            Console.WriteLine(response.StatusCode);
            if (response.StatusCode == HttpStatusCode.OK)
            {
                res = await response.Content.ReadAsStringAsync();
                Console.WriteLine(res);

            }

            return res;
        }

Мой класс: содержимое с прогрессивным потоком

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);
    }
}

Связывается в конструкторе ProgressableStreamContent. Затем вернемся к методу загрузки файла, но когда он вернется, вернемся к sh: Operation not supported on this platform.

Я думаю, что я чего-то не понимаю, и я не нашел никаких документов, связанных с этим. Так не могли бы вы объяснить мне, что не так?

Ответы [ 2 ]

1 голос
/ 23 марта 2020

Вы можете попробовать что-то вроде этого:

using (var multiForm = new MultipartFormDataContent())
    {
      byte[] fileBytes = null;// your file
      var file = new ByteArrayContent(fileBytes);

       ...

      multiForm.Add(file, fileInfo.Name, fileInfo.Name); // Add the file
      var progressContent = new ProgressableStreamContent(multiForm,4096, (sent, total) => {
                //Console.SetCursorPosition(1, 0); // Remove last line
                Console.WriteLine("\bUploading " + ((float)sent / total) * 100f);
            });

       ...

      var response = await client.PostAsync(uploadServiceBaseAdress, progressContent );

       ...
    }
0 голосов
/ 24 марта 2020

Я думаю, это потому, что я не установил точку останова в методе SerializeToStreamAsyn c. Тогда я не смог увидеть загрузку l oop во время отладки.

Более того, SerializeToStreamAsyn c вызывается HttpClient, когда это требуется.

"SerializeToStream метод скопирует буферизованный поток в сетевой поток, когда это требуется HttpClient "

Проверьте этот пост для другого примера, Даррел Миллер дает дополнительную информацию об этом: Публикация пользовательского типа с HttpClient

Вот мой взгляд:

public partial class SomeView : ContentPage
{

    public SomeView()
    {
        InitializeComponent();

        //YOUR CONSTRUCTOR CODE 

    }

    async void StartUploadHandler(object sender, System.EventArgs e)
    {
        styledProgressBar.Progress = 0;

        var fileInfo = (FileInfo)FilesList.SelectedItem;

        Progress<UploadBytesProgress> progressReporter = new Progress<UploadBytesProgress>();

        progressReporter.ProgressChanged += (s, args) => UpdateProgress((double)(100 * args.PercentComplete) / 100);

        fileEndpoint.UploadFiles(fileInfo, progressReporter);
    }

    void UpdateProgress(double obj)
    {
        styledProgressBar.Progress = obj;
    }
}

Настраиваемый HttpContent:

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);
    }
}

Настраиваемая модель выполнения загрузки для репортера:

public class UploadBytesProgress
{
    public UploadBytesProgress(string fileName, int bytesSended, int totalBytes)
    {
        Filename = fileName;
        BytesSended = bytesSended;
        TotalBytes = totalBytes;
    }

    public int TotalBytes { get; private set; }

    public int BytesSended { get; private set; }

    public float PercentComplete { get { return (float)BytesSended / TotalBytes; } }

    public string Filename { get; private set; }

    public bool IsFinished { get { return BytesSended == TotalBytes; } }
}

И вызов http:

public async Task<string> UploadFiles(FileInfo fileInfo, IProgress<UploadBytesProgress> progessReporter)
    {
        string res = null;
        IAndroidFileHelper androidFileHelper = DependencyService.Get<IAndroidFileHelper>();

        using (var client = new HttpClient())
        {
            using (var multiForm = new MultipartFormDataContent())
            {
                var bytesFile = androidFileHelper.LoadLocalFile(fileInfo.FullName);
                ByteArrayContent byteArrayContent = new ByteArrayContent(bytesFile);

                multiForm.Add(byteArrayContent, fileInfo.Name, fileInfo.Name);

                var progressContent = new ProgressableStreamContent(multiForm, 4096, (sent, total) =>
                {
                    UploadBytesProgress args = new UploadBytesProgress("SERVEUR URL FOR UPLOAD", (int)sent, (int)total);
                    progessReporter.Report(args);
                });


                var uploadServiceBaseAdress = "SERVEUR URL FOR UPLOAD";

                var response = await client.PostAsync(uploadServiceBaseAdress, progressContent);
                Console.WriteLine(response.StatusCode);

                if (response.StatusCode == HttpStatusCode.OK)
                {
                    res = await response.Content.ReadAsStringAsync();
                    Console.WriteLine(res);

                }
                else
                {
                    throw new Exception(response.ReasonPhrase);
                }

                return res;
            }
        }
    }

Каким образом существует другой способ загрузки файла с отчетом о ходе работы:

https://docs.microsoft.com/fr-fr/dotnet/api/system.net.webclient.uploadprogresschanged?view=netframework-4.8

https://forums.xamarin.com/discussion/comment/199958/#Comment_199958

Надеюсь, это поможет некоторым людям, столкнувшимся с той же ситуацией, что и я.

...