2013-04-29 22 views
34

miałem to działa .. ale zauważyłem raz pliki byłem przesyłaniem uzyskać większe (około 4000K) kontroler nie będzie nazywany ..Jak przesłać duże pliki za pomocą MVC 4?

więc dodałem w wyrwy, które stałej ten problem .. ale teraz, kiedy otwórz plik pełen śmieciowych znaków ...

Jaki jest więc właściwy sposób przesyłania dużych plików za pomocą plupload/MVC 4?

Tu jest mój bieżący kod

$(document).ready(function() { 

    var uploader = new plupload.Uploader({ 
     runtimes: 'html5', 
     browse_button: 'pickfiles', 
     container: 'container', 
    // max_file_size: '20000mb', 
     url: '@Url.Action("Upload", "Home")', 
     chunk_size: '4mb', 
     //filters: [ 
     // { title: "Excel files", extensions: "xls,xlsx" }, 
     // { title: "Text files", extensions: "txt" } 
     //], 
     multiple_queues: true, 
     multipart: true, 
     multipart_params: { taskId: '' } 
    }); 

a kontroler

[HttpPost] 
    public ActionResult Upload(int? chunk, string name, string taskId) 
    { 
     string filePath = ""; 
     var fileUpload = Request.Files[0]; 
     var uploadPath = Server.MapPath("~/App_Data/Uploads"); 
     chunk = chunk ?? 0; 
     string uploadedFilePath = Path.Combine(uploadPath, name); 
     var fileName = Path.GetFileName(uploadedFilePath); 

try 
     { 
      using (var fs = new FileStream(filePath, chunk == 0 ? FileMode.Create : FileMode.Append)) 
      { 
       var buffer = new byte[fileUpload.InputStream.Length]; 
       fileUpload.InputStream.Read(buffer, 0, buffer.Length); 
       fs.Write(buffer, 0, buffer.Length); 
      } 

      //Log to DB for future processing 
      InstanceExpert.AddProcessStart(filePath, Int32.Parse(taskId)); 
     } 
+1

Plik 4MB powinien być obsługiwany bez dzielenia na porcje w ASP.NET. Może być konieczne zwiększenie maksymalnego rozmiaru wysyłanego pliku lub zwiększenie czasu wykonania. –

+0

ten największy plik, jaki mam, to jest 7268k. Czy potrzebuję chunkingu? Lub co mogę zmienić? – punkouter

+0

Zmień 'maxRequestLength' w pliku web.config. Spójrz na http://stackoverflow.com/a/288675/254973 dla przykładu tego, co musisz tam zmienić. Następnie usuń opcję 'chunk_size' z javascript, więc plUpload nie wysyła przesyłanych plików. –

Odpowiedz

55

W web.config trzeba te (2GB dookoła):

<system.web> 
    <compilation debug="true" targetFramework="4.5" /> 
    <httpRuntime targetFramework="4.5" maxRequestLength="2147483647" executionTimeout="1600" requestLengthDiskThreshold="2147483647" /> 
    <security> 
     <requestFiltering> 
     <requestLimits maxAllowedContentLength="2147483647" /> 
     </requestFiltering> 
    </security> 
    ... 
</system.web> 
+0

Dzięki Shane! To działało dla mojej aplikacji "Intranetowej", ale używam targetFramework = "4.0" , więc moja sekcja nie ma sekcji . W końcu miałem limit między 300 MB a 700 MB. Nie w pełni przetestowałem, by znaleźć dokładny limit. – Colin

+4

Myślę, że masz na myśli nie . Może jest inaczej w różnych wersjach. – jwize

+0

dla strony internetowej to system.web – ShaneKm

11

Aktualna wersja

Zgodnie ze szczegółowym opisem błędu IIS 8.0, który jest wersją używaną w momencie, w którym napisałem tę odpowiedź, musisz zweryfikować ustawienie configuration/system.webServer/security/requestFiltering/requestLimits @maxAllowedContentLength w pliku ApplicationHost.config lub Web.config. Oznacza to, że musisz dołączyć:

<requestLimits maxAllowedContentLength="20971520000"></requestLimits> 

wewnątrz konfiguracji/system.webServer/security/requestFiltering drzewa znaczników. Tylko w przypadku, gdy brakuje wyobraźni, by zwizualizować gdzie to idzie, pełny blok kodu idzie tak:

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

Visual Studio 2010/.Net Framework 4 i zanim

Jest również możliwe, że starsze aplikacje internetowe utworzone za pomocą VS2008/10 i/lub .Net Framework 3.5/4 mogą nadal poszukiwać tej konfiguracji przez configuration/system.web/httpRuntime @maxRequestLength, ale jak wynika z połączonej strony, nie jest ona już dostępna, chociaż HttpRuntime Class, która nie zastosowanie do tego scenariusza, nadal istnieje od .Net Framework 1.1. Jeśli tak jest, trzeba to:

<httpRuntime maxRequestLength="20971520000" /> 

wewnątrz konfiguracji/system.web/httpRuntime tag drzewa. Po raz kolejny, tylko w przypadku, gdy brak zrozumiałości, aby dowiedzieć się, gdzie robi się włożeniu pełny blok kod wygląda mniej więcej tak: liczba wielkość

<configuration> 
    <system.web> 
     <httpRuntime maxRequestLength="20971520000" /> 
    </system.web> 
</configuration> 

plik jest po prostu dowolna liczba (20000 MB - nie 20 GB, które byłoby raczej 21, 474,836,480), aby pokazać jako demo. Jeśli nie kodujesz strony internetowej dla ciasnej grupy bezpieczeństwa, która musi przesłać duże pliki, nie powinieneś pozwalać na przesyłanie tego dużego pliku do twojego serwera.

4

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, tak jak to omówiono wcześniej.

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