Лучший способ для потоковой передачи файлов в ASP.NET - PullRequest
34 голосов
/ 04 марта 2009

Какой лучший способ для потоковой передачи файлов с использованием ASP.NET?

Для этого существуют различные методы, и в настоящее время я использую метод Response.TransmitFile () внутри обработчика http, который напрямую отправляет файл в браузер. Это используется для различных целей, в том числе для отправки FLV-файлов извне рута на встроенный Flash-видеоплеер.

Однако это не похоже на надежный метод. В частности, существует странная проблема с Internet Explorer (7) , когда браузер просто зависает после просмотра видео или двух. Нажатие на любые ссылки и т. Д. Не дает никакого эффекта, и единственный способ восстановить работу сайта - закрыть браузер и снова открыть его.

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

Попробовав несколько разных вещей, я обнаружил, что у меня работает следующий метод:

Response.WriteFile(path);
Response.Flush();
Response.Close();
Response.End();

Это решает проблему, упомянутую выше, и просмотр видео больше не приводит к зависанию Internet Explorer.

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

Мне интересно услышать, как другие разработчики транслируют большие файлы в ASP.NET и, в частности, потоковые видеофайлы FLV.

Ответы [ 4 ]

51 голосов
/ 04 марта 2009

Я бы взял вещи за пределы конвейера "aspx". В частности, я бы написал обработчик run (ashx или сопоставленный через config), который выполняет минимум и просто записывает ответ в виде фрагментов. Обработчик будет принимать входные данные из строки / формы запроса в обычном режиме, находить объект для потоковой передачи и передавать данные (используя локальный буфер умеренного размера в цикле). Простой (неполный) пример, показанный ниже:

public void ProcessRequest(HttpContext context) {
    // read input etx
    context.Response.Buffer = false;
    context.Response.ContentType = "text/plain";
    string path = @"c:\somefile.txt";
    FileInfo file = new FileInfo(path);
    int len = (int)file.Length, bytes;
    context.Response.AppendHeader("content-length", len.ToString());
    byte[] buffer = new byte[1024];
    Stream outStream = context.Response.OutputStream;
    using(Stream stream = File.OpenRead(path)) {
        while (len > 0 && (bytes =
            stream.Read(buffer, 0, buffer.Length)) > 0)
        {
            outStream.Write(buffer, 0, bytes);
            len -= bytes;
        }
    }
}
10 голосов
/ 04 марта 2009

Взгляните на следующую статью Отслеживание и возобновление загрузки больших файлов в ASP.NET , которая даст вам больше возможностей, чем просто открыть поток и вытолкнуть все биты.

Протокол http поддерживает ранжированные байтовые запросы и возобновляемые загрузки, и многие потоковые клиенты (например, видеоплееры или Adobe pdf) могут и будут пытаться разделить их на части, сэкономив пропускную способность и предоставив вашим пользователям лучший опыт.

Не тривиально, но время потрачено не зря.

8 голосов
/ 04 марта 2009

Попробуйте открыть файл в виде потока, затем с помощью Response.OutputStream.Write (). Например:

Редактировать: Плохо, я забыл, что запись занимает байтовый буфер. Fixed

byte [] buffer = new byte[1<<16] // 64kb
int bytesRead = 0;
using(var file = File.OpenRead(path))
{
   while((bytesRead = file.Read(buffer, 0, buffer.Length)) != 0)
   {
        Response.OutputStream.Write(buffer, 0, bytesRead);
   }
}
Response.Flush();
Response.Close();
Response.End();

Редактировать 2: Вы пробовали это? Он должен работать.

3 голосов
/ 05 марта 2009

После попытки множества различных комбинаций, включая код, размещенный в различных ответах, кажется, что установка Response.Buffer = true перед вызовом TransmitFile сделала свое дело, и веб-приложение теперь намного более отзывчиво в Internet Explorer.

В данном конкретном случае расширение SWF также сопоставлено с ASP.NET, и мы используем собственный обработчик в нашем веб-приложении для чтения файлов с диска и последующей отправки их в браузер с помощью Response.TransmitFile (). , У нас есть видеоплеер на основе флэш-памяти для воспроизведения видеофайлов, которые также являются SWF-файлами, и я думаю, что все эти действия проходят через обработчик без буферизации - вот что могло вызывать странные вещи в IE.

...