it-swarm.com.de

Wie lade ich große Dateien mit MVC 4 hoch?

Ich hatte es funktioniert .. aber ich bemerkte, sobald die Dateien, die ich hochlud, größer wurden (ca. 4000k), würde der Controller nicht aufgerufen werden ..

Also habe ich in Chunking hinzugefügt, was dieses Problem behoben hat. Aber jetzt, wenn ich die Datei öffne, ist sie voll mit Müllzeichen.

Was ist also der richtige Weg, um große Dateien mit plupload/MVC 4 hochzuladen?

Hier ist mein aktueller Code

  $(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: '' }
    });

und der Controller

  [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));
        }
43
punkouter

In web.config benötigen Sie diese (2 GB):

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

Aktuelle Version

Entsprechend der detaillierten Fehlerbeschreibung von IIS 8.0, der Version, die ich zum Zeitpunkt des Schreibens dieser Antwort verwendet habe, müssen Sie configuration/system.webServer/security/requestFiltering/requestLimits @ maxAllowedContentLength-Einstellung in der Datei ApplicationHost.config oder Web.config Das bedeutet, dass Sie Folgendes einschließen müssen:

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

in der Tag-Struktur configuration/system.webServer/security/requestFiltering. Nur für den Fall, dass Sie sich nicht vorstellen können, wohin es geht, sieht der vollständige Codeblock folgendermaßen aus:

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

Visual Studio 2010/.Net Framework 4 und früher

Es ist auch möglich, dass ältere Webanwendungen, die mit VS2008/10 und/oder .Net Framework 3.5/4 erstellt wurden, diese Konfiguration weiterhin über configuration/system.web/httpRuntime @ maxRequestLength suchen, was jedoch belegt ist Von der verknüpften Seite ist sie nicht mehr verfügbar, obwohl HttpRuntime Class , das für dieses Szenario nicht gilt, seit .NET Framework 1.1 noch vorhanden ist. In diesem Fall müssen Sie Folgendes angeben:

<httpRuntime maxRequestLength="20971520000" />

im Tag-Baum configuration/system.web/httpRuntime. Nur für den Fall, dass Sie nicht verstehen können, wo es eingefügt wird, sieht der vollständige Codeblock folgendermaßen aus:

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

Die Dateigröße ist nur eine willkürliche Zahl (20.000 MB - nicht 20 GB, das wären eher 21.474.836.480), die als Demo angezeigt werden soll. Sofern Sie die Website nicht für eine strenge Sicherheitsgruppe codieren, die große Dateien hochladen muss, sollten Sie nicht zulassen, dass diese große Datei auf Ihren Webserver hochgeladen wird.

15
Prince Deekay

Die Lösung basiert auf Jonathans Code hier . Wenn Sie eine große Datei, beispielsweise eine 1-GB-Videodatei, hochladen möchten, müssen Sie die Datei auslagern und sie über mehrere Anforderungen senden (bei einer Anforderung tritt eine Zeitüberschreitung auf). Zuerst legen Sie das maximale Limit für Client- und Serverseite in Web.config fest, wie in anderen Antworten erläutert.

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

und

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

dann chunk die Datei und sende jedes Chuck, warte auf Antwort und sende das nächste Chunk. hier ist der html ( VideoDiv arbeit als upload panel), javascript (jQuery) und controller code.

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

Javascript-Code zum Einspannen, Aufrufen des Controllers und Aktualisieren der Fortschrittsanzeige:

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

und hier ist der Upload-Controller zum Speichern des Chucnk in ("App_Data/Videos/Temp") und zum späteren Zusammenführen und Speichern in ("App_Data/Videos"):

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

Wenn jedoch zwei Benutzer gleichzeitig Dateien mit demselben Namen hochladen, tritt ein Problem auf, und Sie müssen dieses Problem beheben. Wenn Sie responseText lesen, können Sie einen Fehler und eine Ausnahme abfangen und abschneiden.

11
Aryan Firouzian