Загрузка больших файлов

Я разработчик ASP.net-любитель, работаю на своей первой работе (веб-сайт друзей). ASP.net v4.0 с использованием VS2010.

Его компания делает 3D-модели (на 3D-принтере). Веб-сайт в настоящее время находится в разработке, но его можно найти здесь. Я был бы первым, кто признал бы, что код был немного поспешен и взломан, но мой друг вполне доволен тем, что у него есть.

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

Я начал с использования встроенного тега <asp:FileUpload ID="FileUpload1" runat="server" /> и анимированного gif-изображения, похожего на идею, описанную в Руководство Джо Стагнера - спасибо, Джо, мне очень нравятся ваши презентации.

Это работало нормально для небольшого тестового файла, но не дает никаких указаний о ходе загрузки. Поэтому я попытался улучшить свое решение, используя идеи, разработанные Сунасарой Имдадхусеном в его статья проекта кода. Мой код загрузки выглядит так:

Task t = Task.Factory.StartNew(() =>
{
    byte[] buffer = new byte[UPLOAD_BUFFER_BYTE_SIZE];

    // Upload the file in chunks so that we can measure how long it is taking.
    using (FileStream fs = new FileStream(Path.Combine(newQuotePath, filename), FileMode.Create))
    {
        DateTime stopwatch = DateTime.Now;

        while (stats.Uploaded < stats.TotalSize)
        {
            int bytecount = postedFile.InputStream.Read(buffer, 0, UPLOAD_BUFFER_BYTE_SIZE);
            fs.Write(buffer, 0, bytecount);

            stats.Uploaded += bytecount;

            double dRate = UPLOAD_BUFFER_BYTE_SIZE / Math.Abs((DateTime.Now - stopwatch).TotalSeconds);
            stats.Rate = (int)(Math.Min(dRate, int.MaxValue));

            // Sleep is for debugging only!
            //System.Threading.Thread.Sleep(2000);

            stopwatch = DateTime.Now;
        }
    }
}, TaskCreationOptions.LongRunning);

Где stats — это ссылка на класс, который хранится как переменная сеанса и доступен из функции javascript, работающей в setInterval(...) (во время загрузки) с помощью PageMethod:

[System.Web.Services.WebMethod]
[System.Web.Script.Services.ScriptMethod]
public static UploadStatus GetFileUploadStatus()
{
    UploadStatus stats = (UploadStatus)HttpContext.Current.Session["UploadFileStatus"];

    if ((stats != null) && (stats.IsReady))
    {
        return stats;
    }
    else
    {
        return null;
    }
}

Это сработало на моей локальной машине (используя спящий режим для замедления загрузки). Поэтому я опубликовал его на нашем хосте 123-Reg, но он не работал должным образом. Анимированный gif появляется, когда начинается загрузка, но индикатор выполнения не начинает двигаться. Элемент управления вводом файла и кнопка отправки (в IFrame), которые должны быть отключены, как только начнется загрузка, требуют времени, чтобы отключиться. Тогда веб-страница просто висит там. Подождав некоторое время, я нажал кнопку обновления страницы. Когда страница обновилась, она показала, что мой тестовый файл был успешно загружен. Я попробовал файл размером 16 КБ и файл размером 1,6 МБ.

Поскольку это работало на моем локальном компьютере, я подозреваю, что это происходит из-за того, что наш хост веб-сайта (123-Reg) использует веб-ферму.

В любом случае, я думал, что это будет легко, но это не так, и поэтому я искал некоторые индикаторы загрузки с открытым исходным кодом. Я просмотрел NeatUpload, но там написано: "По умолчанию NeatUpload не работает должным образом в веб-садах или веб-фермы», а также говорится, чтобы заставить его работать на веб-ферме: «Укажите один и тот же случайный атрибут decryptionKey из 32 шестнадцатеричных цифр в разделе Web.config каждого сервера». Но я не думаю, что у меня есть доступ к файлам конфигурации сервера 123-Reg(?).

Мой друг предположил, что, возможно, мы могли бы использовать такой сервис, как Dropbox, но я посмотрел и понятия не имею, как добавить его на наш веб-сайт. Это может быть хорошим вариантом, поскольку они могут быть оптимизированы для загрузки.

Любые советы или предложения будут очень признательны - спасибо.


РЕДАКТИРОВАТЬ: История до сих пор ... все еще борется с этим.

Я подробно изучил использование Dropbox (и других поставщиков облачных хранилищ, таких как SkyDrive и т. д.). Похоже, что эти службы предназначены для предоставления приложений, которые взаимодействуют с хранилищем отдельных пользователей. Я хотел, чтобы все пользователи могли загружать файлы в папку MY dropbox, но без общего доступа (клиенты не должны иметь доступ к файлам дизайна других клиентов). В любом случае, я продолжил, настроил учетную запись Dropbox, установил Sharpbox SDK и перепрограммировал свой код загрузки (бит внутри действие задачи). Казалось, что это работает нормально на моем локальном компьютере, это было немного медленнее, потому что оно загружалось на сервер dropbox (мне не нужен Thread.Sleep). Я опубликовал сайт на сервере 123-Reg и получил такой же бесполезный опыт, как и раньше.

До сих пор я тестировал IE9, и я только что попробовал его с Chrome и заметил забавную вещь. Сразу после нажатия кнопки загрузки, но до того, как страница обновилась, Chrome показал диалоговое окно «% завершения загрузки» в левом нижнем углу. Это дошло до 100%, затем мои элементы управления начали показывать какие-то действия, прежде чем вся страница снова начала зависать.

Согласно MSDN HttpPostedFile: "По умолчанию все запросы, включая поля форм и загруженные файлы размером более 256 КБ, буферизуются на диск"

Значит ли это, что моя задача запускается после мучительной части ожидания загрузки (которая на самом деле происходит между клиентом и буфером)? Если это так, то не имеет смысла делать это более болезненным, отправляя файл в дропбокс, верно? И мой индикатор выполнения отслеживает прогресс неправильного бита?

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


person Ben    schedule 02.08.2012    source источник
comment
Вместо этого используйте облака, если это не дорого для вас, или купите собственный сервер для хостинга. Похоже, хостинг-провайдер ограничивает размер запроса.   -  person Johnny_D    schedule 02.08.2012
comment
Согласно сообщению serialseb: Asp.net всегда загружает весь контент запроса, как только вы используете HttpRequest.InputStream, поэтому Я предполагаю, что это может вызвать некоторые проблемы для меня.   -  person Ben    schedule 04.08.2012


Ответы (1)


Это может быть немного излишним, но вы можете изучить инструмент загрузки файлов jQuery от BluImp (демонстрационный сайт здесь: http://blueimp.github.com/jQuery-File-Upload/) — разработчик по имени Макс Павлов модифицировал исходную версию (изначально для технологий, отличных от dotnet) для использования в MVC 3.

Его можно найти здесь, в git hub https://github.com/maxpavlov/jQuery-File-Upload.MVC3 . Я успешно реализовал это как в MVC 3, так и в MVC 4 Beta. Единственное, что мне нужно было сделать, чтобы заставить его работать эффективно в MVC 4, — это удалить часть кода ClientDependancy (это DLL, которая обрабатывает связывание и минимизацию файлов JS и CSS), поскольку это воспроизводит функциональность уже в MVC 4, но не в MVC. 3. Кроме того, я добавил несколько страниц в вики на GitHub с описанием того, что я сделал, хотя это и не завершено. Если вы решите пойти по этому пути, я могу обновить некоторые детали с моими последними выводами. Мои заметки об интеграции MVC 4 на данный момент можно найти здесь https://github.com/maxpavlov/jQuery-File-Upload.MVC3/wiki/MVC-4---EnableDefaultBundles .

Кстати, с помощью этого инструмента мне удалось загрузить файлы размером до 2 Гб, и он оказался довольно гибким!

person Luke Baughan    schedule 03.08.2012