2009-06-20 24 views
6

Będę potrzebować klienta (użytkownika końcowego) za pośrednictwem przeglądarki do przesłania dużych plików (np. Podobnego do scenariusza Youtube, który przesyła duże pliki wideo), rozmiar pliku nie powinien być większy niż 500 MB.Problem z przesyłaniem pliku

Używam ASP.Net + C# + VSTS + IIS 7.0 jako mojej platformy programistycznej. Jakieś pomysły lub dobre praktyki dotyczące rozwiązywania problemów z przesyłaniem dużych plików? Wszelkie próbki referencyjne lub dokumenty są mile widziane.

Odpowiedz

2

Odpowiedzi na this related question polecam SWFUpload lub NeatUpload do przesyłania dużych plików przez przeglądarkę. NeatUpload jest komponentem ASP.NET, który może dobrze pasować do twojego środowiska.

Istnieje również JUpload.

+0

Dzięki Colin, jeszcze jedno pytanie, dlaczego preferowane jest używanie rozwiązania opartego na RIA, ponieważ lepsza wydajność przesyłania lub coś innego? – George2

+1

Obsługa przeglądarki dla standardowego HTTP nie zezwala na takie rzeczy, jak określanie, które typy plików są dozwolone, podobnie rzeczy takie jak paski postępu są lepiej obsługiwane przez flash/java –

+0

1. Czy za pomocą kontroli FileUpload nie można określić typu pliku? Jestem zdezorientowany. 2. Myślę, że używanie rozwiązania nie opartego na RIA może również zaimplementować pasek postępu, np. Jak przesyłać załącznik jest Gmail. Nie oznacza to, że używanie zwykłego Http nie może zaimplementować paska postępu. Wszelkie komentarze? – George2

2

Musisz ustawić maxRequestLength odpowiednio obsłużyć duży plik, a także ustawić executionTimeout tak że IIS nie zrezygnować z żądania, w pliku web.config

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

Znacznie szczegoly są here w Jona Artykuł Gallowy o przesyłaniu dużych plików.

Oto artykuł na MSDN o przesyłanie plików w ASP.NET 2.0

+0

Dzięki TheVillageIdiot, jeszcze jedno pytanie, dlaczego preferowane jest rozwiązanie oparte na RIA, ponieważ lepsza wydajność przesyłania lub coś innego? – George2

+1

Myślę, że dzięki RIA możesz dać użytkownikowi lepszą informację zwrotną dla długotrwałej operacji. – TheVillageIdiot

+0

Dzięki, 1. Czy tylko korzyści dla użytkownika? Żadna skuteczność przesyłania ani inne korzyści nie są uwzględniane? 2. Dlaczego korzystanie z rozwiązań nie opartych na RIA może nie dawać dobrego doświadczenia użytkownikom, czy mógłby mi Pan podać przykład? – George2

1

Prawie wszystkie strony, które obsługiwać bardzo duże przesłane zrobić domyślnie używając Adobe Flash. Zwykle wracają do prostego ładowania przeglądarki, ale zarządzanie rzeczami sprawia, że ​​postęp w bieżącym przesyłaniu jest znacznie łatwiejszy do zrobienia w pamięci flash.

+0

Jestem zdezorientowany, sugerujesz, że używamy flasha, czy nie? – George2

+2

Myślę, że zaleceniem jest użycie flash (lub java), ale zezwalaj na standardowe wysyłanie HTTP, jeśli użytkownik nie ma flasha/java dostępnego –

+0

, dlaczego preferowane jest używanie rozwiązania opartego na flash (lub java), ponieważ lepsza wydajność przesyłania lub coś innego? – George2

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

To nie zadziała w IIS7! httpRuntime jest dla IIS6 i poniżej. Poprawny sposób w celu umożliwienia przesyłania dużych plików IIS7 jest:

1) dodać następujące linie pliku web.config:

[Web.config] maxAllowedContentLength atrybut IIS7

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

2) Następnie otwórz plik C: \ Windows \ System32 \ inetsrv \ config \ applicationHost.config i znajdź linię:

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

overrideModeDefault należy Zezwalaj.

+0

Jedno pytanie o znaczenie parametru "executionTimeout" w IIS 6. Czy to oznacza maksymalny czas całego procesu ładowania? Lub oznacza to maksymalny czas bezczynności (bezczynność mam na myśli, że porcja plików nie jest przenoszona z przeglądarki na serwer, więc jeśli nadal przesyłać fragmenty plików, nawet jeśli powolny, nie będzie końca czasu)? – George2

+0

Kolejne pytanie brzmi: czy istnieje parametr do określenia limitu czasu w IIS 7? – George2

+0

Jestem prawie pewien, że exectutionTimeout dotyczy również IIS7. W związku z pierwszym pytaniem: limit czasu określa maksymalną liczbę sekund, przez jaką żądanie może zostać wykonane, zanim zostanie automatycznie wyłączony przez ASP.NET. np. jeśli przesyłanie nie zostanie zakończone w 110 sekund (domyślnie) ASP wyłączy proces. –

0

Miałem ten problem i znalazłem rozwiązanie oparte na Jonathan's code here. Jest pewien problem z jego kodem, ale tutaj jest moje rozwiązanie. Jeśli chcesz przesłać duży plik, taki jak plik o wielkości 1 Gb/s, musisz wyrzucić plik i wysłać go przez kilka żądań (jedno żądanie daje czas). najpierw ustaw maksymalny limit dla klienta i serwera.

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

i

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

następnie fragment pliku i wysłać każdy uchwyt, czekać na odpowiedź i wysłać następny kawałek. tutaj jest kod javascript i kontroler.

<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> 

kod Javascript by Chuck kontroler połączeń i aktualizacji 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); 
     }); 

i tutaj jest kontrolerem przesyłać do przechowywania chucnk w ("App_Data/Filmy/Temp"), a następnie połączyć je i przechowywać w („App_Data/Filmy”):

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

Jednakże, jeśli dwóch użytkowników w tym samym czasie przesyłania plików o tej samej nazwie, nie będzie jakiś problem, i trzeba obsługiwać ten problem. Czytając responseText, możesz złapać błąd i wyjątek i przyciąć go.

Powiązane problemy