Transmisión de cargas de archivos grandes a ASP.NET MVC


Para una aplicación en la que estoy trabajando, necesito permitir que el usuario cargue archivos muy grandes, es decir, potencialmente muchos gigabytes, a través de nuestro sitio web. Desafortunadamente, ASP.NET MVC parece cargar toda la solicitud en la RAM antes de comenzar a darle servicio not no es exactamente ideal para una aplicación de este tipo. En particular, tratando de eludir el problema a través de código como el siguiente:

if (request.Method == "POST")
{
    request.ContentLength = clientRequest.InputStream.Length;
    var rgbBody = new byte[32768];

    using (var requestStream = request.GetRequestStream())
    {
        int cbRead;
        while ((cbRead = clientRequest.InputStream.Read(rgbBody, 0, rgbBody.Length)) > 0)
        {
            fileStream.Write(rgbBody, 0, cbRead);
        }
    }
}

No logra eludir la mentalidad buffer-the-request-into-RAM. ¿Hay una manera fácil de solucionar esto comportamiento?

Author: Benjamin Pollack, 2009-06-26

2 answers

Resulta que mi código inicial era básicamente correcto; el único cambio requerido era cambiar

request.ContentLength = clientRequest.InputStream.Length;

A

request.ContentLength = clientRequest.ContentLength;

Las primeras secuencias en toda la solicitud para determinar la longitud del contenido; la última simplemente comprueba el encabezado Content-Length, que solo requiere que los encabezados se hayan enviado en su totalidad. Esto permite que IIS comience a transmitir la solicitud casi de inmediato, lo que elimina por completo el problema original.

 23
Author: Benjamin Pollack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-10 21:36:54

Claro, puedes hacer esto. Ver Cargas de archivos restful con HttpWebRequest e IHttpHandler. He estado usando este método durante unos años y tengo un sitio que ha sido probado con archivos de al menos varios gigabytes. Esencialmente, desea crear su propio IHttpHandler, que es más fácil de lo que parece.

En pocas palabras, se crea una clase que implementa el IHttpHandler interfaz, lo que significa que debe admitir la propiedad IsReusable y el método ProcessRequest. En la parte superior de eso, hay un cambio menor en su web.config, y funciona como un encanto. En esta etapa en el ciclo de vida de la solicitud, todo el archivo que se carga no se carga en la memoria, por lo que los pasos prolijamente fuera de problemas de memoria.

Tenga en cuenta que en la web.config,

<httpHandlers>
 <add verb="*" path="DocumentUploadService.upl" validate="false" type="TestUploadService.FileUploadHandler, TestUploadService"/>
</httpHandlers>

El archivo referenciado, DocumentUploadService.upl, en realidad no existe. Eso es solo para dar una extensión alternativa para que la solicitud no sea interceptada por el controlador estándar. Usted apunta su file upload forma a esa ruta, pero luego su clase FileUploadHandler inicia y realmente recibe el archivo.

Actualización: En realidad, el código que uso es diferente de ese artículo, y creo que me topé con la razón por la que funciona. Utilizo la clase HttpPostedFile, en la que los archivos "se cargan en formato MIME multipart/form-data. De forma predeterminada, todas las solicitudes, incluidos los campos de formulario y los archivos cargados, de más de 256 KB, se almacenan en búfer en el disco, en lugar de guardarse en el servidor memoria."

if (context.Request.Files.Count > 0)
{
    string tempFile = context.Request.PhysicalApplicationPath;
    for(int i = 0; i < context.Request.Files.Count; i++)
    {
        HttpPostedFile uploadFile = context.Request.Files[i];
        if (uploadFile.ContentLength > 0)
        {
            uploadFile.SaveAs(string.Format("{0}{1}{2}",
              tempFile,"Upload\\", uploadFile.FileName));
        }
    }
}
 15
Author: RedFilter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-25 23:08:44