web-dev-qa-db-fra.com

Meilleure façon de diffuser des fichiers en ASP.NET

Quelle est la meilleure façon de diffuser des fichiers en utilisant ASP.NET?

Il semble y avoir différentes méthodes pour cela, et j'utilise actuellement la méthode Response.TransmitFile () à l'intérieur d'un gestionnaire http, qui envoie le fichier directement au navigateur. Ceci est utilisé pour diverses choses, y compris l'envoi de FLV depuis l'extérieur de la racine Web vers un lecteur vidéo Flash intégré.

Cependant, cela ne semble pas être une méthode fiable. En particulier, il y a un problème étrange avec Internet Explorer (7) , où le navigateur se bloque juste après qu'une ou deux vidéos ont été visionnées. Cliquer sur un lien, etc. n'a aucun effet, et la seule façon de faire fonctionner à nouveau le site est de fermer le navigateur et de le rouvrir.

Cela se produit également dans d'autres navigateurs, mais beaucoup moins fréquemment. Sur la base de certains tests de base, je soupçonne que cela est lié à la façon dont les fichiers sont diffusés ... peut-être que la connexion n'est pas fermée correctement, ou quelque chose du genre.

Après avoir essayé quelques choses différentes, j'ai constaté que la méthode suivante fonctionne pour moi:

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

Cela résout le problème mentionné ci-dessus et la visualisation de vidéos ne provoque plus le blocage d'Internet Explorer.

Cependant, je crois comprendre que Response.WriteFile () charge d'abord le fichier en mémoire, et étant donné que certains fichiers en cours de streaming peuvent potentiellement être assez volumineux, cela ne semble pas être une solution idéale.

Je suis intéressé à savoir comment d'autres développeurs diffusent des fichiers volumineux dans ASP.NET, et en particulier, des fichiers vidéo FLV en streaming.

34
Mun

Je prendrais des choses en dehors du pipeline "aspx". En particulier, j'écrirais un gestionnaire d'exécution (ashx, ou mappé via config), qui fait le travail minimum, et écrit simplement dans la réponse en morceaux. Le gestionnaire accepterait l'entrée de la chaîne de requête/du formulaire comme normal, localiserait l'objet à diffuser et diffuserait les données (en utilisant un tampon local de taille moyenne dans une boucle). Un exemple simple (incomplet) illustré ci-dessous:

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;
        }
    }
}
51
Marc Gravell

Jetez un œil à l'article suivant Suivi et reprise des téléchargements de fichiers volumineux dans ASP.NET qui vous donnera plus de détails que d'ouvrir un flux et de jeter tous les bits.

Le protocole http prend en charge les demandes d'octets à distance et les téléchargements pouvant être repris, et de nombreux clients de streaming (comme les lecteurs vidéo ou Adobe pdf) peuvent et essaieront de les segmenter, économisant de la bande passante et offrant à vos utilisateurs une meilleure expérience.

Pas anodin, mais c'est du temps bien dépensé.

10
Robert Paulson

Essayez d'ouvrir le fichier en tant que flux, puis utilisez Response.OutputStream.Write (). Par exemple:

Edit: Mon mauvais, j'ai oublié que Write prend un tampon d'octets. Fixé

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: Avez-vous essayé cela? Ça devrait marcher.

8
Randolpho

Après avoir essayé de nombreuses combinaisons différentes, y compris le code publié dans les différentes réponses, il semble que définir Response.Buffer = true avant d'appeler TransmitFile a fait l'affaire et l'application Web est maintenant beaucoup plus réactive dans Internet Explorer.

Dans ce cas particulier, l'extension SWF est également mappée sur ASP.NET, et nous utilisons un gestionnaire personnalisé dans notre application Web pour lire les fichiers à partir du disque, puis les envoyer au navigateur à l'aide de Response.TransmitFile (). Nous avons un lecteur vidéo basé sur flash pour lire des fichiers vidéo qui sont également des fichiers SWF, et je pense que le fait de passer toute cette activité par le gestionnaire sans mise en mémoire tampon est ce qui a pu provoquer des choses étranges dans IE.

3
Mun