2009-03-03 13 views
34

Qual è il modo migliore per eseguire lo streaming di file utilizzando ASP.NET?Il modo migliore per eseguire lo streaming di file in ASP.NET

Sembra che ci siano vari metodi per questo, e attualmente sto usando il metodo Response.TransmitFile() all'interno di un gestore http, che invia direttamente il file al browser. Questo è usato per varie cose, incluso l'invio di FLV dall'esterno del webroot a un player video Flash incorporato.

Tuttavia, questo non sembra un metodo affidabile. In particolare, c'è uno strano problema con Internet Explorer (7), in cui il browser si blocca solo dopo aver visto un video o due. Fare clic su qualsiasi link, ecc. Non ha alcun effetto e l'unico modo per far funzionare nuovamente le cose sul sito è chiudere il browser e riaprirlo.

Ciò si verifica anche in altri browser, ma molto meno frequentemente. Basandomi su alcuni test di base, sospetto che questo abbia a che fare con il modo in cui i file vengono trasmessi in streaming ... forse la connessione non viene chiusa correttamente o qualcosa del genere.

Dopo aver provato un paio di cose diverse, ho trovato che il seguente metodo funziona per me:

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

Questo aggira il problema di cui sopra, e la visualizzazione di video non causa più Internet Explorer da appendere.

Tuttavia, la mia comprensione è che Response.WriteFile() carica il file prima in memoria, e dato che alcuni file in streaming potrebbero potenzialmente essere piuttosto grandi, questa non sembra una soluzione ideale.

Mi interessa sapere come altri sviluppatori eseguono lo streaming di file di grandi dimensioni in ASP.NET e, in particolare, lo streaming di file video FLV.

+0

Ecco un approccio che ho utilizzato che aggiunge la funzionalità di download ripristinabile che sarebbe utile se lo streaming video: http://stackoverflow.com/a/6475414/222748 – Michael

risposta

8

Provare ad aprire il file come stream, quindi utilizzare Response.OutputStream.Write(). Ad esempio:

Modifica: Il mio male, ho dimenticato che Scrittura richiede un buffer di byte. Risolto

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

Edit 2: Hai provato questo? Dovrebbe funzionare.

+0

Grazie, ma non penso che funzioni ... Risposta. OutputStream.Write non accetta un parametro Stream (non in ASP.NET 2.0 in ogni caso), solo un array di byte, che richiede il caricamento del file in memoria e quindi non è migliore della soluzione WriteFile. – Mun

+0

Sì, non stavo prestando attenzione quando ho scritto il codice. Risolto – Randolpho

+2

Per quanto riguarda l'array di byte, non è necessario caricare l'intero flusso in memoria. Il codice che ho usato al massimo 64kb di memoria (più spese generali minori) durante lo streaming. – Randolpho

51

Prenderei le cose al di fuori della pipeline "aspx". In particolare, scriverei un gestore gestito (ashx o mappato via config), che funziona lo minimo e scrive semplicemente nella risposta in blocchi. Il gestore accetta l'input dalla stringa di query/modulo normalmente, individua l'oggetto sul flusso e esegue il flusso dei dati (utilizzando un buffer locale di dimensioni moderate in un ciclo). Un semplice (incompleto) esempio illustrato di seguito:

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; 
     } 
    } 
} 
+1

Un downvote senza una motivazione non aiuta nessuno. Pensavo che la tua risposta fosse buona. +1 per riportarti alla parità. – Guy

+0

Non sono uno che ha downvoted, ma ho pensato di far notare che la domanda iniziale in realtà afferma che il codice viene usato in un gestore http ... Grazie comunque per il suggerimento. – Mun

+1

Per modificare il nome del file, dopo la riga: 'context.Response ...' aggiungere questa riga: 'context.Response.AppendHeader (" content-Disposition "," attachment; filename = "+ filename);' – MaciejLisCK

10

Date un'occhiata al seguente articolo Tracking and Resuming Large File Downloads in ASP.NET che vi darà più in profondità di un semplice aprire un flusso e Chuck fuori tutti i bit.

Il protocollo http supporta richieste di byte a distanza e download ripristinabili, e molti client di streaming (come lettori video o Adobe pdf) possono e cercheranno di ridurli, risparmiando larghezza di banda e offrendo agli utenti un'esperienza migliore.

Non banale, ma è tempo ben speso.

3

Dopo aver provato molte combinazioni diverse, incluso il codice pubblicato nelle varie risposte, sembra che impostare Response.Buffer = true prima di chiamare TransmitFile ha fatto il trucco e l'applicazione Web ora è molto più reattiva in Internet Explorer.

In questo caso particolare, l'estensione SWF viene mappata anche su ASP.NET e stiamo utilizzando un gestore personalizzato nella nostra applicazione Web per leggere i file dal disco e quindi inviarli al browser utilizzando Response.TransmitFile (). Abbiamo un lettore video basato su flash per riprodurre file video che sono anche SWF, e penso che avere tutta questa attività attraverso il gestore senza buffering sia ciò che potrebbe aver causato strani eventi in IE.

Problemi correlati