2009-06-20 7 views
6

J'ai besoin de client (utilisateur final) via le navigateur pour télécharger de gros fichiers (par exemple similaire au scénario de Youtube qui télécharge de gros fichiers vidéo), la taille du fichier ne doit pas dépasser 500M octets. J'utilise ASP.Net + C# + VSTS + IIS 7.0 comme plate-forme de développement. Des idées ou de bonnes pratiques sur la façon de gérer le gros problème de téléchargement de fichiers? Tous les échantillons de référence ou documents sont appréciés.problème de téléchargement de fichier

Répondre

2

Les réponses à this related question recommandent SWFUpload ou NeatUpload pour télécharger de gros fichiers via le navigateur. NeatUpload est un composant ASP.NET qui pourrait bien s'adapter à votre environnement.

Il existe également JUpload.

+0

Merci Colin, une autre question, pourquoi utiliser une solution basée sur RIA est préférable, parce que de meilleures performances de téléchargement ou quelque chose d'autre? – George2

+1

La prise en charge du navigateur HTTP standard ne permet pas de spécifier quels types de fichiers sont autorisés, et d'autres choses comme les progressbars sont mieux supportées par flash/java. –

+0

1. L'utilisation du contrôle FileUpload ne peut pas spécifier le type de fichier? Je suis confus. 2. Je pense que l'utilisation d'une solution non basée sur RIA pourrait également implémenter une barre de progression, comme la manière dont nous téléchargeons des pièces jointes dans Gmail. Donc, cela ne signifie pas utiliser Http plaine ne peut pas implémenter la barre de progression. Des commentaires? – George2

2

Vous devez définir maxRequestLength pour gérer de manière appropriée gros fichier et également mis en executionTimeout de sorte que IIS ne renonce pas à la demande, dans le fichier web.config

<system.web> 
    <httpRuntime executionTimeout="300" maxRequestLength="512000" /> 
</system.web> 

Beaucoup plus detailes sont here à Jon L'article de Gallowy sur le téléchargement de gros fichiers.

Voici l'article sur MSDN à propos de téléchargement de fichiers dans asp.net 2.0

+0

Merci TheVillageIdiot, une autre question, pourquoi utiliser la solution basée sur RIA est préférable, parce que de meilleures performances de téléchargement ou autre chose? – George2

+1

Je pense qu'avec RIA vous pouvez donner un meilleur retour pour l'opération de longue durée à l'utilisateur. – TheVillageIdiot

+0

Merci, 1. si seulement l'expérience utilisateur avantages? Aucune performance de téléchargement ou d'autres avantages consideratinos? 2. Pourquoi l'utilisation d'une solution non basée sur RIA ne peut pas avoir une bonne expérience utilisateur, pourriez-vous me donner un exemple s'il vous plaît? – George2

1

Presque tous les sites qui gèrent les téléchargements très grandes le font par défaut à l'aide d'Adobe Flash. Habituellement, ils reviennent à un simple téléchargement de navigateur, mais la gestion des choses la progression du téléchargement en cours est nettement plus facile à faire en flash.

+0

Je suis confus, vous nous suggérez d'utiliser flash ou non? – George2

+2

Je pense que la recommandation est utiliser flash (ou java), mais permettre le téléchargement HTTP standard si l'utilisateur n'a pas flash/java disponible –

+0

pourquoi utiliser flash (ou java) solution basée est préférable, parce que de meilleures performances de téléchargement ou autre chose? – George2

6
<system.web> 
     <httpRuntime executionTimeout="300" maxRequestLength="512000" /> 
    </system.web> 

Cela ne fonctionnera pas dans IIS7! httpRuntime est pour IIS6 et ci-dessous. La bonne façon de permettre téléchargements de fichiers volumineux dans IIS7 est:

1) Ajoutez les lignes suivantes dans le fichier web.config:

[Web.config] maxAllowedContentLength attribut pour IIS7

<system.webServer> 
    <security > 
     <requestFiltering> 
      <requestLimits maxAllowedContentLength="1024000000" /> 
     </requestFiltering> 
    </security> 
</system.webServer> 

2) Ensuite, ouvrez le fichier C: \ Windows \ System32 \ inetsrv \ config \ applicationHost.config et trouvez la ligne:

<section name="requestFiltering" overrideModeDefault="Allow" /> 

overrideModeDefault devrait être Autoriser.

+0

Une question sur la signification du paramètre "executionTimeout" dans IIS 6. Cela signifie-t-il le temps maximum de tout le processus de téléchargement? Ou cela signifie le temps d'inactivité max (inactif, je veux dire aucun morceau de fichier est transféré du navigateur au serveur, donc si continuer à transférer des morceaux de fichiers, même si lent, il n'y aura pas de temps mort)? – George2

+0

Une autre question est, existe-t-il un paramètre pour spécifier le délai d'attente dans IIS 7? – George2

+0

Je suis presque sûr qu'exectutionTimeout s'applique également à IIS7. En ce qui concerne votre première question: le délai d'attente spécifie le nombre maximal de secondes qu'une requête est autorisée à exécuter avant d'être automatiquement arrêté par ASP.NET. c'est-à-dire si votre téléchargement n'est pas terminé en 110 secondes (par défaut) ASP arrêtera le processus. –

0

J'ai rencontré ce problème et trouvé la solution basée sur Jonathan's code here. Il y a un problème avec son code, mais voici ma solution. Si vous voulez télécharger un fichier volumineux, quelque chose comme un fichier 1Gbyte, vous devez chuck le fichier et l'envoyer à travers plusieurs demandes (une demande donne un délai). Vous devez d'abord définir la limite maximale pour le client et le serveur.

<system.webServer> 
<security> 
    <requestFiltering> 
    <requestLimits maxAllowedContentLength="2147483647" /> 
    </requestFiltering> 
</security> 
<system.webServer> 

et

<system.web> 
    <httpRuntime targetFramework="4.5" maxRequestLength="2147483647" /> 
</system.web> 

puis morceau le fichier, et envoyer chaque mandrin, attendez la réponse et envoyer le morceau suivant. voici le code javascript et le code du contrôleur.

<div id="VideoDiv"> 
     <label>Filename:</label> 
     <input type="file" id="fileInput" /><br/><br/> 
     <input type="button" id="btnUpload" value="Upload a presentation"/><br/><br/> 
     <div id="progressbar_container" style="width: 100%; height: 30px; position: relative; background-color: grey; display: none"> 
      <div id="progressbar" style="width: 0%; height: 100%; position: absolute; background-color: green"></div> 
      <span id="progressbar_label" style="position: absolute; left: 35%; top: 20%">Uploading...</span> 
     </div> 
    </div> 

code Javascript au mandrin, contrôleur d'appel et mise à jour progressbar:

 var progressBarStart = function() { 
      $("#progressbar_container").show(); 
     } 

     var progressBarUpdate = function (percentage) { 
      $('#progressbar_label').html(percentage + "%"); 
      $("#progressbar").width(percentage + "%"); 
     } 

     var progressBarComplete = function() { 
      $("#progressbar_container").fadeOut(500); 
     } 

     var file; 

     $('#fileInput').change(function(e) { 
      file = e.target.files[0]; 
     }); 

     var uploadCompleted = function() { 
      var formData = new FormData(); 
      formData.append('fileName', file.name); 
      formData.append('completed', true); 

      var xhr2 = new XMLHttpRequest(); 
      xhr2.onload = function() { 
       progressBarUpdate(100); 
       progressBarComplete(); 
      } 
      xhr2.open("POST", "/Upload/UploadComplete?fileName=" + file.name + "&complete=" + 1, true); 
      xhr2.send(formData); 
     } 

     var multiUpload = function(count, counter, blob, completed, start, end, bytesPerChunk) { 
      counter = counter + 1; 
      if (counter <= count) { 
       var chunk = blob.slice(start, end); 
       var xhr = new XMLHttpRequest(); 
       xhr.onload = function() { 
        start = end; 
        end = start + bytesPerChunk; 
        if (count == counter) { 
         uploadCompleted(); 
        } else { 
         var percentage = (counter/count) * 100; 
         progressBarUpdate(percentage); 
         multiUpload(count, counter, blob, completed, start, end, bytesPerChunk); 
        } 
       } 
       xhr.open("POST", "/Upload/MultiUpload?id=" + counter.toString() + "&fileName=" + file.name, true); 
       xhr.send(chunk); 
      } 
     } 

     $("#VideoDiv").on("click", "#btnUpload", function() { 
      var blob = file; 
      var bytesPerChunk = 3757000; 
      var size = blob.size; 

      var start = 0; 
      var end = bytesPerChunk; 
      var completed = 0; 
      var count = size % bytesPerChunk == 0 ? size/bytesPerChunk : Math.floor(size/bytesPerChunk) + 1; 
      var counter = 0; 
      progressBarStart(); 
      multiUpload(count, counter, blob, completed, start, end, bytesPerChunk); 
     }); 

et voici le contrôleur de téléchargement pour enregistrer le chucnk dans ("App_Data/Vidéos/Temp"), puis de les fusionner et stocker dans (« App_Data/Vidéos »):

public class UploadController : Controller 
{ 
    private string videoAddress = "~/App_Data/Videos"; 

    [HttpPost] 
    public string MultiUpload(string id, string fileName) 
    { 
     var chunkNumber = id; 
     var chunks = Request.InputStream; 
     string path = Server.MapPath(videoAddress+"/Temp"); 
     string newpath = Path.Combine(path, fileName+chunkNumber); 
     using (FileStream fs = System.IO.File.Create(newpath)) 
     { 
      byte[] bytes = new byte[3757000]; 
      int bytesRead; 
      while ((bytesRead=Request.InputStream.Read(bytes,0,bytes.Length))>0) 
      { 
       fs.Write(bytes,0,bytesRead); 
      } 
     } 
     return "done"; 
    } 

    [HttpPost] 
    public string UploadComplete(string fileName, string complete) 
    { 
     string tempPath = Server.MapPath(videoAddress + "/Temp"); 
     string videoPath = Server.MapPath(videoAddress); 
     string newPath = Path.Combine(tempPath, fileName); 
     if (complete=="1") 
     { 
      string[] filePaths = Directory.GetFiles(tempPath).Where(p=>p.Contains(fileName)).OrderBy(p => Int32.Parse(p.Replace(fileName, "$").Split('$')[1])).ToArray(); 
      foreach (string filePath in filePaths) 
      { 
       MergeFiles(newPath, filePath); 
      } 
     } 
     System.IO.File.Move(Path.Combine(tempPath, fileName),Path.Combine(videoPath,fileName)); 
     return "success"; 
    } 

    private static void MergeFiles(string file1, string file2) 
    { 
     FileStream fs1 = null; 
     FileStream fs2 = null; 
     try 
     { 
      fs1 = System.IO.File.Open(file1, FileMode.Append); 
      fs2 = System.IO.File.Open(file2, FileMode.Open); 
      byte[] fs2Content = new byte[fs2.Length]; 
      fs2.Read(fs2Content, 0, (int) fs2.Length); 
      fs1.Write(fs2Content, 0, (int) fs2.Length); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex.Message + " : " + ex.StackTrace); 
     } 
     finally 
     { 
      if (fs1 != null) fs1.Close(); 
      if (fs2 != null) fs2.Close(); 
      System.IO.File.Delete(file2); 
     } 
    } 
} 

Cependant, si deux utilisateurs à télécharger des fichiers même temps, avec le même nom, il y aura un problème, et vous devez gérer ce problème. En lisant responseText, vous pouvez attraper une erreur et une exception et la couper.

Questions connexes