Процесс загрузки файла - PullRequest
4 голосов
/ 21 апреля 2010

Я пытался отслеживать ход загрузки файла, но продолжаю зацикливаться (загрузка из приложения C #, а не с веб-страницы).

Я пытался использовать WebClient как таковой:

class Program
{
    static volatile bool busy = true;

    static void Main(string[] args)
    {
        WebClient client = new WebClient();
        // Add some custom header information

        client.Credentials = new NetworkCredential("username", "password");
        client.UploadProgressChanged += client_UploadProgressChanged;
        client.UploadFileCompleted += client_UploadFileCompleted;

        client.UploadFileAsync(new Uri("http://uploaduri/"), "filename");

        while (busy)
        {
            Thread.Sleep(100);
        }
        Console.WriteLine("Done: press enter to exit");
        Console.ReadLine();
    }

    static void client_UploadFileCompleted(object sender, UploadFileCompletedEventArgs e)
    {
        busy = false;
    }

    static void client_UploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
    {
        Console.WriteLine("Completed {0} of {1} bytes", e.BytesSent, e.TotalBytesToSend);
    }
}

Файл загружается, и прогресс распечатывается, но прогресс происходит намного быстрее, чем фактическая загрузка, и при загрузке большого файла прогресс достигнет максимума в течение нескольких секунд, но фактическая загрузка занимает несколько минут (это не так. просто жду ответа, все данные еще не поступили на сервер).

Поэтому я попытался использовать HttpWebRequest для потоковой передачи данных (я знаю, что это не является точным эквивалентом загрузки файла, так как он не создает multipart/form-data содержимого, но служит иллюстрацией моей проблемы). Я установил AllowWriteStreamBuffering = false и установил ContentLength, как подсказывает этот вопрос / ответ :

class Program
{
    static void Main(string[] args)
    {
        FileInfo fileInfo = new FileInfo(args[0]);
        HttpWebRequest client = (HttpWebRequest)WebRequest.Create(new Uri("http://uploadUri/"));
        // Add some custom header info
        client.Credentials = new NetworkCredential("username", "password");

        client.AllowWriteStreamBuffering = false;
        client.ContentLength = fileInfo.Length;
        client.Method = "POST";

        long fileSize = fileInfo.Length;
        using (FileStream stream = fileInfo.OpenRead())
        {
            using (Stream uploadStream = client.GetRequestStream())
            {
                long totalWritten = 0;
                byte[] buffer = new byte[3000];
                int bytesRead = 0;
                while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    uploadStream.Write(buffer, 0, bytesRead);
                    uploadStream.Flush();
                    Console.WriteLine("{0} of {1} written", totalWritten += bytesRead, fileSize);
                }
            }
        }
        Console.WriteLine("Done: press enter to exit");
        Console.ReadLine();
    }
}

Запрос не запускается до тех пор, пока весь файл не будет записан в поток, и уже показывает полный прогресс на момент его запуска (я использую fiddler для проверки этого). Я также попытался установить SendChunked в true (с настройкой ContentLength и без нее). Кажется, что данные все еще кэшируются перед отправкой по сети.

Что-то не так с одним из этих подходов или, может быть, есть другой способ, которым я могу отслеживать ход загрузки файлов из приложения Windows?

Ответы [ 2 ]

3 голосов
/ 30 января 2011

Обновлен:

Это консольное приложение работает для меня, как и ожидалось:

static ManualResetEvent done = new ManualResetEvent(false);
    static void Main(string[] args)
    {
        WebClient client = new WebClient();
        client.UploadProgressChanged += new UploadProgressChangedEventHandler(client_UploadProgressChanged);
        client.UploadFileCompleted += new UploadFileCompletedEventHandler(client_UploadFileCompleted);
        client.UploadFileAsync(new Uri("http://localhost/upload"), "C:\\test.zip");

        done.WaitOne();

        Console.WriteLine("Done");
    }

    static void client_UploadFileCompleted(object sender, UploadFileCompletedEventArgs e)
    {
        done.Set();
    }

    static void client_UploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
    {
        Console.Write("\rUploading: {0}%  {1} of {2}", e.ProgressPercentage, e.BytesSent, e.TotalBytesToSend);
    }
1 голос
/ 02 июля 2011

Я считаю, что ваш запрос идет по сети. Я обнаружил, что Fiddler 2.3.4.4 не показывает частичные запросы, но MS Network Monitor может отображать отдельные пакеты, но не в локальной петле (так что сервер и клиент должны быть на разных машинах, если вы хотите проверить).

Я сталкиваюсь с той же проблемой скрытой буферизации здесь и считаю, что один из параметров службы WCF неправильно настроен на сервере для потоковой передачи. Мне любопытно, какой тип веб-службы вы реализуете, привязки и т. Д. По сути, сервер буферизирует все сообщение, а затем передает его на обработку, поэтому может возникнуть большая задержка после отправки последнего байта от клиента.

В случае, когда я смотрел, где веб-служба была REST-службой WCF, файл буферизовался в следующем месте перед передачей в качестве аргумента потока методу веб-службы:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\root\86e02ad6\c1702d08\uploads*.post
...