Saltar al contenido

¿Cómo cargar archivos grandes usando MVC 4?

Después de de nuestra extensa selección de datos pudimos resolver este atascamiento que presentan algunos de nuestros lectores. Te regalamos la respuesta y deseamos que te sea de gran apoyo.

Solución:

En web.config, necesita estos (2GB en todas partes):


    
    
    
      
        
      
    
    ...

Versión actual

De acuerdo con la descripción detallada del error de IIS 8.0, que es la versión que usé en el momento en que escribí esta respuesta, debe verificar la configuración / system.webServer / security / requestFiltering /[email protected] en el archivo ApplicationHost.config o Web.config. Eso significa que debes incluir:


dentro de la configuración / system.webServer / security / requestFiltering árbol de etiquetas. En caso de que le falte la imaginación para visualizar a dónde va, el bloque de código completo es el siguiente:


    
        
            
                
            
        
    

Visual Studio 2010 / .Net Framework 4 y versiones anteriores

También es posible que las aplicaciones web heredadas creadas con VS2008 / 10 y / o .Net Framework 3.5 / 4 todavía busquen esta configuración a través de configuration / system.web /[email protected], pero como lo demuestra la página vinculada, ya no está disponible, aunque HttpRuntime Class, que no se aplica a este escenario, todavía existe desde .Net Framework 1.1. Si este es el caso, debe incluir:


dentro del árbol de etiquetas de configuration / system.web / httpRuntime. Una vez más, en caso de que no tenga la comprensión para averiguar dónde se inserta, el bloque de código completo se parece a lo siguiente:


    
        
    

El número de tamaño del archivo es solo un número arbitrario (20.000 MB, no 20 GB, que sería 21.474.836.480) para mostrarlo como demostración. A menos que esté codificando el sitio web para un grupo de seguridad estricto que necesita cargar archivos grandes, no debe permitir que se carguen archivos tan grandes en su servidor web.

La solución se basa en el código de Jonathan aquí. Si desea cargar un archivo grande, algo así como un archivo de video de 1 Gbyte, debe tirar el archivo y enviarlo a través de varias solicitudes (una solicitud da tiempo de espera). primero establece el límite máximo para el cliente y el servidor en Web.config como se discutió en otras respuestas.


 
  
    
  
 

y


  

luego fragmenta el archivo y envía cada mandril, espera la respuesta y envía el siguiente fragmento. aquí está el html (VideoDiv funciona como panel de carga), javascript (jQuery) y código del controlador.

    




Código Javascript para chuck, llamar al controlador y actualizar la barra de progreso:

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

y aquí está el controlador de carga para almacenar el chucnk en ("App_Data / Videos / Temp") y luego fusionarlos y almacenarlos en ("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);
        
    

Sin embargo, si dos usuarios al mismo tiempo cargan archivos con el mismo nombre, habrá algún problema y tendrá que manejar este problema. Al leer responseText, puede detectar algún error y excepción y recortarlo.

Comentarios y valoraciones

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *