web-dev-qa-db-fra.com

Comment télécharger des fichiers volumineux à l'aide de MVC 4?

Je l'ai fait fonctionner .. mais j'ai remarqué une fois que les fichiers que je téléchargeais deviennent plus gros (environ 4000k) le contrôleur ne serait pas appelé ..

J'ai donc ajouté des morceaux qui ont résolu ce problème .. mais maintenant, lorsque j'ouvre le fichier, il est plein de caractères inutiles ...

Alors, quelle est la bonne façon de télécharger des fichiers volumineux avec plupload/MVC 4?

Voici mon code actuel

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

et le contrôleur

  [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

Dans web.config, vous en avez besoin (2 Go tout autour):

<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

Version actuelle

Selon la description détaillée de l'erreur de IIS 8.0, qui est la version que j'ai utilisée au moment où j'ai écrit cette réponse, vous devez vérifier la configuration/system.webServer/security/requestFiltering/requestLimits @ paramètre maxAllowedContentLength dans le fichier ApplicationHost.config ou Web.config . Cela signifie que vous devez inclure:

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

à l'intérieur de l'arborescence des balises configuration/system.webServer/security/requestFiltering. Juste au cas où vous manquez d'imagination pour visualiser où il va, le bloc de code complet se présente comme suit:

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

Visual Studio 2010/.Net Framework 4 et avant

Il est également possible que les applications Web héritées créées avec VS2008/10 et/ou .Net Framework 3.5/4 recherchent toujours cette configuration via configuration/system.web/httpRuntime @ maxRequestLength, mais comme en témoignent par la page liée, il n'est plus disponible, bien que HttpRuntime Class , qui ne s'applique pas à ce scénario, existe toujours depuis .Net Framework 1.1. Si tel est le cas, vous devez inclure:

<httpRuntime maxRequestLength="20971520000" />

à l'intérieur de l'arborescence des balises configuration/system.web/httpRuntime. Encore une fois, juste au cas où vous ne pourriez pas comprendre où il est inséré, le bloc de code complet ressemble à ceci:

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

Le numéro de taille du fichier est juste un nombre arbitraire (20 000 Mo - pas 20 Go, ce qui serait plutôt 21 474 836 480) à afficher comme une démo. À moins que vous ne codiez le site Web pour un groupe de sécurité restreint qui a besoin de télécharger des fichiers volumineux, vous ne devez pas autoriser le téléchargement d'une taille de fichier aussi importante sur votre serveur Web.

15
Prince Deekay

La solution est basée sur le code de Jonathan ici . Si vous souhaitez télécharger un fichier volumineux, quelque chose comme un fichier vidéo de 1 Go, vous devez jeter le fichier et l'envoyer via plusieurs demandes (une demande donne un délai). vous définissez d'abord la limite maximale pour le côté client et serveur dans Web.config comme indiqué dans les autres réponses.

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

et

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

puis découpez le fichier et envoyez chaque mandrin, attendez la réponse et envoyez le prochain. voici le code html ( VideoDiv comme panneau de téléchargement), javascript (jQuery) 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 pour mandrin, appeler le contrôleur et mettre à jour la barre de progression:

        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 stocker le chucnk dans ("App_Data/Videos/Temp") et les fusionner plus tard et les stocker dans ("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);
        }
    }
}

Cependant, si deux utilisateurs téléchargent en même temps des fichiers portant le même nom, il y aura un problème et vous devrez gérer ce problème. En lisant responseText, vous pouvez détecter des erreurs et des exceptions et les supprimer.

11
Aryan Firouzian